2011-04-27 11:58:34 +00:00
|
|
|
/*
|
2013-08-18 14:16:15 +00:00
|
|
|
* Copyright 2011-2013 Blender Foundation
|
2011-04-27 11:58:34 +00:00
|
|
|
*
|
2013-08-18 14:16:15 +00:00
|
|
|
* 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
|
2011-04-27 11:58:34 +00:00
|
|
|
*
|
2013-08-18 14:16:15 +00:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2011-04-27 11:58:34 +00:00
|
|
|
*
|
2013-08-18 14:16:15 +00:00
|
|
|
* 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
|
2014-12-25 02:50:24 +01:00
|
|
|
* limitations under the License.
|
2011-04-27 11:58:34 +00:00
|
|
|
*/
|
|
|
|
|
Cycles: Make all #include statements relative to cycles source directory
The idea is to make include statements more explicit and obvious where the
file is coming from, additionally reducing chance of wrong header being
picked up.
For example, it was not obvious whether bvh.h was refferring to builder
or traversal, whenter node.h is a generic graph node or a shader node
and cases like that.
Surely this might look obvious for the active developers, but after some
time of not touching the code it becomes less obvious where file is coming
from.
This was briefly mentioned in T50824 and seems @brecht is fine with such
explicitness, but need to agree with all active developers before committing
this.
Please note that this patch is lacking changes related on GPU/OpenCL
support. This will be solved if/when we all agree this is a good idea to move
forward.
Reviewers: brecht, lukasstockner97, maiself, nirved, dingto, juicyfruit, swerner
Reviewed By: lukasstockner97, maiself, nirved, dingto
Subscribers: brecht
Differential Revision: https://developer.blender.org/D2586
2017-03-28 20:39:14 +02:00
|
|
|
#include "render/mesh.h"
|
|
|
|
#include "render/object.h"
|
|
|
|
#include "render/scene.h"
|
|
|
|
#include "render/camera.h"
|
2011-04-27 11:58:34 +00:00
|
|
|
|
Cycles: Make all #include statements relative to cycles source directory
The idea is to make include statements more explicit and obvious where the
file is coming from, additionally reducing chance of wrong header being
picked up.
For example, it was not obvious whether bvh.h was refferring to builder
or traversal, whenter node.h is a generic graph node or a shader node
and cases like that.
Surely this might look obvious for the active developers, but after some
time of not touching the code it becomes less obvious where file is coming
from.
This was briefly mentioned in T50824 and seems @brecht is fine with such
explicitness, but need to agree with all active developers before committing
this.
Please note that this patch is lacking changes related on GPU/OpenCL
support. This will be solved if/when we all agree this is a good idea to move
forward.
Reviewers: brecht, lukasstockner97, maiself, nirved, dingto, juicyfruit, swerner
Reviewed By: lukasstockner97, maiself, nirved, dingto
Subscribers: brecht
Differential Revision: https://developer.blender.org/D2586
2017-03-28 20:39:14 +02:00
|
|
|
#include "blender/blender_sync.h"
|
|
|
|
#include "blender/blender_session.h"
|
|
|
|
#include "blender/blender_util.h"
|
2011-04-27 11:58:34 +00:00
|
|
|
|
Cycles: Make all #include statements relative to cycles source directory
The idea is to make include statements more explicit and obvious where the
file is coming from, additionally reducing chance of wrong header being
picked up.
For example, it was not obvious whether bvh.h was refferring to builder
or traversal, whenter node.h is a generic graph node or a shader node
and cases like that.
Surely this might look obvious for the active developers, but after some
time of not touching the code it becomes less obvious where file is coming
from.
This was briefly mentioned in T50824 and seems @brecht is fine with such
explicitness, but need to agree with all active developers before committing
this.
Please note that this patch is lacking changes related on GPU/OpenCL
support. This will be solved if/when we all agree this is a good idea to move
forward.
Reviewers: brecht, lukasstockner97, maiself, nirved, dingto, juicyfruit, swerner
Reviewed By: lukasstockner97, maiself, nirved, dingto
Subscribers: brecht
Differential Revision: https://developer.blender.org/D2586
2017-03-28 20:39:14 +02:00
|
|
|
#include "subd/subd_patch.h"
|
|
|
|
#include "subd/subd_split.h"
|
2011-04-27 11:58:34 +00:00
|
|
|
|
Cycles: Make all #include statements relative to cycles source directory
The idea is to make include statements more explicit and obvious where the
file is coming from, additionally reducing chance of wrong header being
picked up.
For example, it was not obvious whether bvh.h was refferring to builder
or traversal, whenter node.h is a generic graph node or a shader node
and cases like that.
Surely this might look obvious for the active developers, but after some
time of not touching the code it becomes less obvious where file is coming
from.
This was briefly mentioned in T50824 and seems @brecht is fine with such
explicitness, but need to agree with all active developers before committing
this.
Please note that this patch is lacking changes related on GPU/OpenCL
support. This will be solved if/when we all agree this is a good idea to move
forward.
Reviewers: brecht, lukasstockner97, maiself, nirved, dingto, juicyfruit, swerner
Reviewed By: lukasstockner97, maiself, nirved, dingto
Subscribers: brecht
Differential Revision: https://developer.blender.org/D2586
2017-03-28 20:39:14 +02:00
|
|
|
#include "util/util_algorithm.h"
|
|
|
|
#include "util/util_foreach.h"
|
|
|
|
#include "util/util_logging.h"
|
|
|
|
#include "util/util_math.h"
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2012-11-03 15:36:02 +00:00
|
|
|
#include "mikktspace.h"
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
|
2016-01-20 09:13:04 +01:00
|
|
|
/* Per-face bit flags. */
|
|
|
|
enum {
|
|
|
|
/* Face has no special flags. */
|
|
|
|
FACE_FLAG_NONE = (0 << 0),
|
|
|
|
/* Quad face was split using 1-3 diagonal. */
|
|
|
|
FACE_FLAG_DIVIDE_13 = (1 << 0),
|
|
|
|
/* Quad face was split using 2-4 diagonal. */
|
|
|
|
FACE_FLAG_DIVIDE_24 = (1 << 1),
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Get vertex indices to create triangles from a given face.
|
|
|
|
*
|
|
|
|
* Two triangles has vertex indices in the original Blender-side face.
|
|
|
|
* If face is already a quad tri_b will not be initialized.
|
|
|
|
*/
|
2017-07-20 23:51:15 +02:00
|
|
|
inline void face_split_tri_indices(const int face_flag,
|
2016-01-20 09:13:04 +01:00
|
|
|
int tri_a[3],
|
|
|
|
int tri_b[3])
|
|
|
|
{
|
|
|
|
if(face_flag & FACE_FLAG_DIVIDE_24) {
|
|
|
|
tri_a[0] = 0;
|
|
|
|
tri_a[1] = 1;
|
|
|
|
tri_a[2] = 3;
|
2017-07-20 23:51:15 +02:00
|
|
|
|
|
|
|
tri_b[0] = 2;
|
|
|
|
tri_b[1] = 3;
|
|
|
|
tri_b[2] = 1;
|
2016-01-20 09:13:04 +01:00
|
|
|
}
|
2017-09-20 19:24:18 +02:00
|
|
|
else {
|
|
|
|
/* Quad with FACE_FLAG_DIVIDE_13 or single triangle. */
|
2016-01-20 09:13:04 +01:00
|
|
|
tri_a[0] = 0;
|
|
|
|
tri_a[1] = 1;
|
|
|
|
tri_a[2] = 2;
|
2017-07-20 23:51:15 +02:00
|
|
|
|
|
|
|
tri_b[0] = 0;
|
|
|
|
tri_b[1] = 2;
|
|
|
|
tri_b[2] = 3;
|
2016-01-20 09:13:04 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-03 15:36:02 +00:00
|
|
|
/* Tangent Space */
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2012-11-03 15:36:02 +00:00
|
|
|
struct MikkUserData {
|
2017-08-25 21:03:50 +02:00
|
|
|
MikkUserData(const BL::Mesh& b_mesh,
|
2018-01-22 14:28:43 +01:00
|
|
|
const char *layer_name,
|
2017-08-25 22:26:04 +02:00
|
|
|
const Mesh *mesh,
|
|
|
|
float3 *tangent,
|
|
|
|
float *tangent_sign)
|
|
|
|
: mesh(mesh),
|
|
|
|
texface(NULL),
|
|
|
|
orco(NULL),
|
|
|
|
tangent(tangent),
|
|
|
|
tangent_sign(tangent_sign)
|
2012-11-03 15:36:02 +00:00
|
|
|
{
|
2018-01-22 14:28:43 +01:00
|
|
|
const AttributeSet& attributes = (mesh->subd_faces.size()) ?
|
|
|
|
mesh->subd_attributes : mesh->attributes;
|
|
|
|
|
|
|
|
Attribute *attr_vN = attributes.find(ATTR_STD_VERTEX_NORMAL);
|
2017-08-25 22:26:04 +02:00
|
|
|
vertex_normal = attr_vN->data_float3();
|
|
|
|
|
2018-01-22 14:28:43 +01:00
|
|
|
if(layer_name == NULL) {
|
|
|
|
Attribute *attr_orco = attributes.find(ATTR_STD_GENERATED);
|
2018-01-21 00:40:42 +01:00
|
|
|
|
|
|
|
if(attr_orco) {
|
|
|
|
orco = attr_orco->data_float3();
|
|
|
|
mesh_texture_space(*(BL::Mesh*)&b_mesh, orco_loc, orco_size);
|
|
|
|
}
|
2017-08-25 22:26:04 +02:00
|
|
|
}
|
|
|
|
else {
|
2018-01-22 14:28:43 +01:00
|
|
|
Attribute *attr_uv = attributes.find(ustring(layer_name));
|
2017-08-25 22:26:04 +02:00
|
|
|
if(attr_uv != NULL) {
|
|
|
|
texface = attr_uv->data_float3();
|
|
|
|
}
|
|
|
|
}
|
2012-10-10 13:02:20 +00:00
|
|
|
}
|
|
|
|
|
2017-08-25 22:26:04 +02:00
|
|
|
const Mesh *mesh;
|
2012-11-03 15:36:02 +00:00
|
|
|
int num_faces;
|
2017-08-25 22:26:04 +02:00
|
|
|
|
|
|
|
float3 *vertex_normal;
|
|
|
|
float3 *texface;
|
|
|
|
float3 *orco;
|
|
|
|
float3 orco_loc, orco_size;
|
|
|
|
|
|
|
|
float3 *tangent;
|
|
|
|
float *tangent_sign;
|
2012-11-03 15:36:02 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static int mikk_get_num_faces(const SMikkTSpaceContext *context)
|
|
|
|
{
|
2017-08-25 22:26:04 +02:00
|
|
|
const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData;
|
2018-01-22 14:28:43 +01:00
|
|
|
if(userdata->mesh->subd_faces.size()) {
|
|
|
|
return userdata->mesh->subd_faces.size();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return userdata->mesh->num_triangles();
|
|
|
|
}
|
2012-11-03 15:36:02 +00:00
|
|
|
}
|
|
|
|
|
2018-01-22 14:28:43 +01:00
|
|
|
static int mikk_get_num_verts_of_face(const SMikkTSpaceContext *context,
|
|
|
|
const int face_num)
|
2012-11-03 15:36:02 +00:00
|
|
|
{
|
2018-01-22 14:28:43 +01:00
|
|
|
const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData;
|
|
|
|
if(userdata->mesh->subd_faces.size()) {
|
|
|
|
const Mesh *mesh = userdata->mesh;
|
|
|
|
return mesh->subd_faces[face_num].num_corners;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return 3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mikk_vertex_index(const Mesh *mesh, const int face_num, const int vert_num)
|
|
|
|
{
|
|
|
|
if(mesh->subd_faces.size()) {
|
|
|
|
const Mesh::SubdFace& face = mesh->subd_faces[face_num];
|
|
|
|
return mesh->subd_face_corners[face.start_corner + vert_num];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return mesh->triangles[face_num * 3 + vert_num];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mikk_corner_index(const Mesh *mesh, const int face_num, const int vert_num)
|
|
|
|
{
|
|
|
|
if(mesh->subd_faces.size()) {
|
|
|
|
const Mesh::SubdFace& face = mesh->subd_faces[face_num];
|
|
|
|
return face.start_corner + vert_num;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return face_num * 3 + vert_num;
|
|
|
|
}
|
2012-11-03 15:36:02 +00:00
|
|
|
}
|
2012-10-10 13:02:20 +00:00
|
|
|
|
2017-08-25 22:26:04 +02:00
|
|
|
static void mikk_get_position(const SMikkTSpaceContext *context,
|
|
|
|
float P[3],
|
|
|
|
const int face_num, const int vert_num)
|
2012-11-03 15:36:02 +00:00
|
|
|
{
|
2017-08-25 22:26:04 +02:00
|
|
|
const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData;
|
|
|
|
const Mesh *mesh = userdata->mesh;
|
2018-01-22 14:28:43 +01:00
|
|
|
const int vertex_index = mikk_vertex_index(mesh, face_num, vert_num);
|
|
|
|
const float3 vP = mesh->verts[vertex_index];
|
2012-11-03 15:36:02 +00:00
|
|
|
P[0] = vP.x;
|
|
|
|
P[1] = vP.y;
|
|
|
|
P[2] = vP.z;
|
|
|
|
}
|
|
|
|
|
2017-08-25 22:26:04 +02:00
|
|
|
static void mikk_get_texture_coordinate(const SMikkTSpaceContext *context,
|
|
|
|
float uv[2],
|
|
|
|
const int face_num, const int vert_num)
|
2012-11-03 15:36:02 +00:00
|
|
|
{
|
2017-08-25 22:26:04 +02:00
|
|
|
const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData;
|
2018-01-22 14:28:43 +01:00
|
|
|
const Mesh *mesh = userdata->mesh;
|
2017-08-25 22:26:04 +02:00
|
|
|
if(userdata->texface != NULL) {
|
2018-01-22 14:28:43 +01:00
|
|
|
const int corner_index = mikk_corner_index(mesh, face_num, vert_num);
|
2017-08-25 22:26:04 +02:00
|
|
|
float3 tfuv = userdata->texface[corner_index];
|
2014-07-29 16:07:05 +06:00
|
|
|
uv[0] = tfuv.x;
|
|
|
|
uv[1] = tfuv.y;
|
|
|
|
}
|
2017-08-25 22:26:04 +02:00
|
|
|
else if(userdata->orco != NULL) {
|
2018-01-22 14:28:43 +01:00
|
|
|
const int vertex_index = mikk_vertex_index(mesh, face_num, vert_num);
|
2017-08-25 22:26:04 +02:00
|
|
|
const float3 orco_loc = userdata->orco_loc;
|
|
|
|
const float3 orco_size = userdata->orco_size;
|
|
|
|
const float3 orco = (userdata->orco[vertex_index] + orco_loc) / orco_size;
|
|
|
|
|
|
|
|
const float2 tmp = map_to_sphere(orco);
|
2015-02-19 12:52:48 +05:00
|
|
|
uv[0] = tmp.x;
|
|
|
|
uv[1] = tmp.y;
|
2013-05-10 12:51:30 +00:00
|
|
|
}
|
2017-08-25 22:26:04 +02:00
|
|
|
else {
|
|
|
|
uv[0] = 0.0f;
|
|
|
|
uv[1] = 0.0f;
|
|
|
|
}
|
2012-11-03 15:36:02 +00:00
|
|
|
}
|
|
|
|
|
2017-08-25 22:26:04 +02:00
|
|
|
static void mikk_get_normal(const SMikkTSpaceContext *context, float N[3],
|
|
|
|
const int face_num, const int vert_num)
|
2012-11-03 15:36:02 +00:00
|
|
|
{
|
2017-08-25 22:26:04 +02:00
|
|
|
const MikkUserData *userdata = (const MikkUserData *)context->m_pUserData;
|
|
|
|
const Mesh *mesh = userdata->mesh;
|
2013-05-11 09:31:58 +00:00
|
|
|
float3 vN;
|
2018-01-22 14:28:43 +01:00
|
|
|
if(mesh->subd_faces.size()) {
|
|
|
|
const Mesh::SubdFace& face = mesh->subd_faces[face_num];
|
|
|
|
if(face.smooth) {
|
|
|
|
const int vertex_index = mikk_vertex_index(mesh, face_num, vert_num);
|
|
|
|
vN = userdata->vertex_normal[vertex_index];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
vN = face.normal(mesh);
|
|
|
|
}
|
2013-05-11 09:31:58 +00:00
|
|
|
}
|
|
|
|
else {
|
2018-01-22 14:28:43 +01:00
|
|
|
if(mesh->smooth[face_num]) {
|
|
|
|
const int vertex_index = mikk_vertex_index(mesh, face_num, vert_num);
|
|
|
|
vN = userdata->vertex_normal[vertex_index];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
const Mesh::Triangle tri = mesh->get_triangle(face_num);
|
|
|
|
vN = tri.compute_normal(&mesh->verts[0]);
|
|
|
|
}
|
2013-05-11 09:31:58 +00:00
|
|
|
}
|
2012-11-03 15:36:02 +00:00
|
|
|
N[0] = vN.x;
|
|
|
|
N[1] = vN.y;
|
|
|
|
N[2] = vN.z;
|
|
|
|
}
|
|
|
|
|
2017-08-25 22:26:04 +02:00
|
|
|
static void mikk_set_tangent_space(const SMikkTSpaceContext *context,
|
|
|
|
const float T[],
|
|
|
|
const float sign,
|
|
|
|
const int face_num, const int vert_num)
|
2012-11-03 15:36:02 +00:00
|
|
|
{
|
2017-08-25 22:26:04 +02:00
|
|
|
MikkUserData *userdata = (MikkUserData *)context->m_pUserData;
|
2018-01-22 14:28:43 +01:00
|
|
|
const Mesh *mesh = userdata->mesh;
|
|
|
|
const int corner_index = mikk_corner_index(mesh, face_num, vert_num);
|
2017-08-25 22:26:04 +02:00
|
|
|
userdata->tangent[corner_index] = make_float3(T[0], T[1], T[2]);
|
|
|
|
if(userdata->tangent_sign != NULL) {
|
|
|
|
userdata->tangent_sign[corner_index] = sign;
|
|
|
|
}
|
2012-11-03 15:36:02 +00:00
|
|
|
}
|
|
|
|
|
2017-08-25 22:26:04 +02:00
|
|
|
static void mikk_compute_tangents(const BL::Mesh& b_mesh,
|
2018-01-22 14:28:43 +01:00
|
|
|
const char *layer_name,
|
2016-01-20 09:13:04 +01:00
|
|
|
Mesh *mesh,
|
|
|
|
bool need_sign,
|
|
|
|
bool active_render)
|
2012-11-03 15:36:02 +00:00
|
|
|
{
|
2017-08-25 22:26:04 +02:00
|
|
|
/* Create tangent attributes. */
|
2018-01-22 14:28:43 +01:00
|
|
|
AttributeSet& attributes = (mesh->subd_faces.size()) ?
|
|
|
|
mesh->subd_attributes : mesh->attributes;
|
2012-11-06 19:59:02 +00:00
|
|
|
Attribute *attr;
|
2014-07-29 16:07:05 +06:00
|
|
|
ustring name;
|
2018-01-22 14:28:43 +01:00
|
|
|
if(layer_name != NULL) {
|
|
|
|
name = ustring((string(layer_name) + ".tangent").c_str());
|
2017-08-25 22:26:04 +02:00
|
|
|
}
|
|
|
|
else {
|
2014-07-29 16:07:05 +06:00
|
|
|
name = ustring("orco.tangent");
|
2017-08-25 22:26:04 +02:00
|
|
|
}
|
|
|
|
if(active_render) {
|
2018-01-22 14:28:43 +01:00
|
|
|
attr = attributes.add(ATTR_STD_UV_TANGENT, name);
|
2017-08-25 22:26:04 +02:00
|
|
|
}
|
|
|
|
else {
|
2018-01-22 14:28:43 +01:00
|
|
|
attr = attributes.add(name, TypeDesc::TypeVector, ATTR_ELEMENT_CORNER);
|
2017-08-25 22:26:04 +02:00
|
|
|
}
|
2012-11-03 15:36:02 +00:00
|
|
|
float3 *tangent = attr->data_float3();
|
2017-08-25 22:26:04 +02:00
|
|
|
/* Create bitangent sign attribute. */
|
2012-11-06 19:59:02 +00:00
|
|
|
float *tangent_sign = NULL;
|
|
|
|
if(need_sign) {
|
|
|
|
Attribute *attr_sign;
|
2014-07-29 16:07:05 +06:00
|
|
|
ustring name_sign;
|
2018-01-22 14:28:43 +01:00
|
|
|
if(layer_name != NULL) {
|
|
|
|
name_sign = ustring((string(layer_name) +
|
2017-08-25 22:26:04 +02:00
|
|
|
".tangent_sign").c_str());
|
|
|
|
}
|
|
|
|
else {
|
2014-07-29 16:07:05 +06:00
|
|
|
name_sign = ustring("orco.tangent_sign");
|
2012-11-06 19:59:02 +00:00
|
|
|
}
|
|
|
|
|
2017-08-25 22:26:04 +02:00
|
|
|
if(active_render) {
|
2018-01-22 14:28:43 +01:00
|
|
|
attr_sign = attributes.add(ATTR_STD_UV_TANGENT_SIGN, name_sign);
|
2017-08-25 22:26:04 +02:00
|
|
|
}
|
|
|
|
else {
|
2018-01-22 14:28:43 +01:00
|
|
|
attr_sign = attributes.add(name_sign,
|
|
|
|
TypeDesc::TypeFloat,
|
|
|
|
ATTR_ELEMENT_CORNER);
|
2012-11-03 15:36:02 +00:00
|
|
|
}
|
2017-08-25 22:26:04 +02:00
|
|
|
tangent_sign = attr_sign->data_float();
|
2012-10-10 13:02:20 +00:00
|
|
|
}
|
2017-08-25 22:26:04 +02:00
|
|
|
/* Setup userdata. */
|
2018-01-22 14:28:43 +01:00
|
|
|
MikkUserData userdata(b_mesh, layer_name, mesh, tangent, tangent_sign);
|
2017-08-25 22:26:04 +02:00
|
|
|
/* Setup interface. */
|
|
|
|
SMikkTSpaceInterface sm_interface;
|
|
|
|
memset(&sm_interface, 0, sizeof(sm_interface));
|
|
|
|
sm_interface.m_getNumFaces = mikk_get_num_faces;
|
|
|
|
sm_interface.m_getNumVerticesOfFace = mikk_get_num_verts_of_face;
|
|
|
|
sm_interface.m_getPosition = mikk_get_position;
|
|
|
|
sm_interface.m_getTexCoord = mikk_get_texture_coordinate;
|
|
|
|
sm_interface.m_getNormal = mikk_get_normal;
|
|
|
|
sm_interface.m_setTSpaceBasic = mikk_set_tangent_space;
|
|
|
|
/* Setup context. */
|
|
|
|
SMikkTSpaceContext context;
|
|
|
|
memset(&context, 0, sizeof(context));
|
|
|
|
context.m_pUserData = &userdata;
|
|
|
|
context.m_pInterface = &sm_interface;
|
|
|
|
/* Compute tangents. */
|
|
|
|
genTangSpaceDefault(&context);
|
2012-10-10 13:02:20 +00:00
|
|
|
}
|
|
|
|
|
2014-03-29 13:03:48 +01:00
|
|
|
/* Create Volume Attribute */
|
|
|
|
|
2016-01-30 14:18:29 +01:00
|
|
|
static void create_mesh_volume_attribute(BL::Object& b_ob,
|
|
|
|
Mesh *mesh,
|
|
|
|
ImageManager *image_manager,
|
|
|
|
AttributeStandard std,
|
|
|
|
float frame)
|
2014-03-29 13:03:48 +01:00
|
|
|
{
|
|
|
|
BL::SmokeDomainSettings b_domain = object_smoke_domain_find(b_ob);
|
|
|
|
|
|
|
|
if(!b_domain)
|
|
|
|
return;
|
2017-05-30 09:43:43 +02:00
|
|
|
|
2018-03-01 11:54:01 +01:00
|
|
|
mesh->volume_isovalue = b_domain.clipping();
|
|
|
|
|
2014-03-29 13:03:48 +01:00
|
|
|
Attribute *attr = mesh->attributes.add(std);
|
|
|
|
VoxelAttribute *volume_data = attr->data_voxel();
|
2018-02-27 22:16:45 +01:00
|
|
|
ImageMetaData metadata;
|
2014-03-29 13:03:48 +01:00
|
|
|
bool animated = false;
|
2018-02-27 22:16:45 +01:00
|
|
|
bool use_alpha = true;
|
2014-03-29 13:03:48 +01:00
|
|
|
|
|
|
|
volume_data->manager = image_manager;
|
2015-07-21 21:58:19 +02:00
|
|
|
volume_data->slot = image_manager->add_image(
|
|
|
|
Attribute::standard_name(std),
|
|
|
|
b_ob.ptr.data,
|
|
|
|
animated,
|
|
|
|
frame,
|
|
|
|
INTERPOLATION_LINEAR,
|
2016-04-20 12:29:08 +02:00
|
|
|
EXTENSION_CLIP,
|
2018-02-27 22:16:45 +01:00
|
|
|
use_alpha,
|
|
|
|
metadata);
|
2014-03-29 13:03:48 +01:00
|
|
|
}
|
|
|
|
|
2016-01-30 14:18:29 +01:00
|
|
|
static void create_mesh_volume_attributes(Scene *scene,
|
|
|
|
BL::Object& b_ob,
|
|
|
|
Mesh *mesh,
|
|
|
|
float frame)
|
2014-03-29 13:03:48 +01:00
|
|
|
{
|
|
|
|
/* for smoke volume rendering */
|
|
|
|
if(mesh->need_attribute(scene, ATTR_STD_VOLUME_DENSITY))
|
2014-06-21 22:18:48 +02:00
|
|
|
create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_DENSITY, frame);
|
2014-03-29 13:03:48 +01:00
|
|
|
if(mesh->need_attribute(scene, ATTR_STD_VOLUME_COLOR))
|
2014-06-21 22:18:48 +02:00
|
|
|
create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_COLOR, frame);
|
2014-03-29 13:03:48 +01:00
|
|
|
if(mesh->need_attribute(scene, ATTR_STD_VOLUME_FLAME))
|
2014-06-21 22:18:48 +02:00
|
|
|
create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_FLAME, frame);
|
2014-03-29 13:03:48 +01:00
|
|
|
if(mesh->need_attribute(scene, ATTR_STD_VOLUME_HEAT))
|
2014-06-21 22:18:48 +02:00
|
|
|
create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_HEAT, frame);
|
2018-02-18 03:13:07 +01:00
|
|
|
if(mesh->need_attribute(scene, ATTR_STD_VOLUME_TEMPERATURE))
|
|
|
|
create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_TEMPERATURE, frame);
|
2014-03-29 13:03:48 +01:00
|
|
|
if(mesh->need_attribute(scene, ATTR_STD_VOLUME_VELOCITY))
|
2014-06-21 22:18:48 +02:00
|
|
|
create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_VELOCITY, frame);
|
2014-03-29 13:03:48 +01:00
|
|
|
}
|
|
|
|
|
2015-02-10 23:40:26 +05:00
|
|
|
/* Create vertex color attributes. */
|
|
|
|
static void attr_create_vertex_color(Scene *scene,
|
|
|
|
Mesh *mesh,
|
2016-01-30 14:18:29 +01:00
|
|
|
BL::Mesh& b_mesh,
|
2016-01-20 09:13:04 +01:00
|
|
|
const vector<int>& nverts,
|
2016-07-16 19:42:28 -04:00
|
|
|
const vector<int>& face_flags,
|
|
|
|
bool subdivision)
|
2015-02-10 23:40:26 +05:00
|
|
|
{
|
2016-07-16 19:42:28 -04:00
|
|
|
if(subdivision) {
|
|
|
|
BL::Mesh::vertex_colors_iterator l;
|
2015-02-10 23:40:26 +05:00
|
|
|
|
2016-07-16 19:42:28 -04:00
|
|
|
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;
|
2015-02-10 23:40:26 +05:00
|
|
|
|
2016-07-16 19:42:28 -04:00
|
|
|
Attribute *attr = mesh->subd_attributes.add(ustring(l->name().c_str()),
|
|
|
|
TypeDesc::TypeColor,
|
|
|
|
ATTR_ELEMENT_CORNER_BYTE);
|
2015-02-10 23:40:26 +05:00
|
|
|
|
2016-07-16 19:42:28 -04:00
|
|
|
BL::Mesh::polygons_iterator p;
|
|
|
|
uchar4 *cdata = attr->data_uchar4();
|
2016-01-20 09:13:04 +01:00
|
|
|
|
2016-07-16 19:42:28 -04:00
|
|
|
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());
|
2018-06-14 17:48:19 +02:00
|
|
|
/* Encode vertex color using the sRGB curve. */
|
|
|
|
*(cdata++) = color_float_to_byte(color_srgb_to_linear_v3(color));
|
2016-07-16 19:42:28 -04:00
|
|
|
}
|
2016-01-20 09:13:04 +01:00
|
|
|
}
|
2016-07-16 19:42:28 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
|
|
|
|
Attribute *attr = mesh->attributes.add(ustring(l->name().c_str()),
|
|
|
|
TypeDesc::TypeColor,
|
|
|
|
ATTR_ELEMENT_CORNER_BYTE);
|
|
|
|
|
|
|
|
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];
|
2017-07-20 23:51:15 +02:00
|
|
|
face_split_tri_indices(face_flags[i], tri_a, tri_b);
|
2016-07-16 19:42:28 -04:00
|
|
|
|
2018-06-14 17:48:19 +02:00
|
|
|
/* Encode vertex color using the sRGB curve. */
|
2016-07-16 19:42:28 -04:00
|
|
|
uchar4 colors[4];
|
2018-06-14 17:48:19 +02:00
|
|
|
colors[0] = color_float_to_byte(color_srgb_to_linear_v3(get_float3(c->color1())));
|
|
|
|
colors[1] = color_float_to_byte(color_srgb_to_linear_v3(get_float3(c->color2())));
|
|
|
|
colors[2] = color_float_to_byte(color_srgb_to_linear_v3(get_float3(c->color3())));
|
2016-07-16 19:42:28 -04:00
|
|
|
if(nverts[i] == 4) {
|
2018-06-14 17:48:19 +02:00
|
|
|
colors[3] = color_float_to_byte(color_srgb_to_linear_v3(get_float3(c->color4())));
|
2016-07-16 19:42:28 -04:00
|
|
|
}
|
2016-01-20 09:13:04 +01:00
|
|
|
|
2016-07-16 19:42:28 -04:00
|
|
|
cdata[0] = colors[tri_a[0]];
|
|
|
|
cdata[1] = colors[tri_a[1]];
|
|
|
|
cdata[2] = colors[tri_a[2]];
|
2015-02-10 23:40:26 +05:00
|
|
|
|
2016-07-16 19:42:28 -04:00
|
|
|
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;
|
2015-02-10 23:40:26 +05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create uv map attributes. */
|
|
|
|
static void attr_create_uv_map(Scene *scene,
|
|
|
|
Mesh *mesh,
|
2016-01-30 14:18:29 +01:00
|
|
|
BL::Mesh& b_mesh,
|
2016-01-20 09:13:04 +01:00
|
|
|
const vector<int>& nverts,
|
2018-01-22 14:28:43 +01:00
|
|
|
const vector<int>& face_flags)
|
2015-02-10 23:40:26 +05:00
|
|
|
{
|
2018-01-22 14:28:43 +01:00
|
|
|
if(b_mesh.tessface_uv_textures.length() != 0) {
|
2015-02-10 23:40:26 +05:00
|
|
|
BL::Mesh::tessface_uv_textures_iterator l;
|
|
|
|
|
|
|
|
for(b_mesh.tessface_uv_textures.begin(l); l != b_mesh.tessface_uv_textures.end(); ++l) {
|
2017-08-25 22:26:04 +02:00
|
|
|
const bool active_render = l->active_render();
|
|
|
|
AttributeStandard uv_std = (active_render)? ATTR_STD_UV: ATTR_STD_NONE;
|
|
|
|
ustring uv_name = ustring(l->name().c_str());
|
|
|
|
AttributeStandard tangent_std = (active_render)? ATTR_STD_UV_TANGENT
|
|
|
|
: ATTR_STD_NONE;
|
|
|
|
ustring tangent_name = ustring(
|
|
|
|
(string(l->name().c_str()) + ".tangent").c_str());
|
|
|
|
|
|
|
|
/* Denotes whether UV map was requested directly. */
|
|
|
|
const bool need_uv = mesh->need_attribute(scene, uv_name) ||
|
|
|
|
mesh->need_attribute(scene, uv_std);
|
|
|
|
/* Denotes whether tangent was requested directly. */
|
|
|
|
const bool need_tangent =
|
|
|
|
mesh->need_attribute(scene, tangent_name) ||
|
|
|
|
(active_render && mesh->need_attribute(scene, tangent_std));
|
2015-02-10 23:40:26 +05:00
|
|
|
|
|
|
|
/* UV map */
|
2017-08-25 22:26:04 +02:00
|
|
|
/* NOTE: We create temporary UV layer if its needed for tangent but
|
|
|
|
* wasn't requested by other nodes in shaders.
|
|
|
|
*/
|
|
|
|
Attribute *uv_attr = NULL;
|
|
|
|
if(need_uv || need_tangent) {
|
|
|
|
if(active_render) {
|
|
|
|
uv_attr = mesh->attributes.add(uv_std, uv_name);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
uv_attr = mesh->attributes.add(uv_name,
|
|
|
|
TypeDesc::TypePoint,
|
|
|
|
ATTR_ELEMENT_CORNER);
|
|
|
|
}
|
2015-02-10 23:40:26 +05:00
|
|
|
|
|
|
|
BL::MeshTextureFaceLayer::data_iterator t;
|
2017-08-25 22:26:04 +02:00
|
|
|
float3 *fdata = uv_attr->data_float3();
|
2015-02-10 23:40:26 +05:00
|
|
|
size_t i = 0;
|
|
|
|
|
|
|
|
for(l->data.begin(t); t != l->data.end(); ++t, ++i) {
|
2016-01-20 09:13:04 +01:00
|
|
|
int tri_a[3], tri_b[3];
|
2017-07-20 23:51:15 +02:00
|
|
|
face_split_tri_indices(face_flags[i], tri_a, tri_b);
|
2016-01-20 09:13:04 +01:00
|
|
|
|
|
|
|
float3 uvs[4];
|
|
|
|
uvs[0] = get_float3(t->uv1());
|
|
|
|
uvs[1] = get_float3(t->uv2());
|
|
|
|
uvs[2] = get_float3(t->uv3());
|
|
|
|
if(nverts[i] == 4) {
|
|
|
|
uvs[3] = get_float3(t->uv4());
|
|
|
|
}
|
|
|
|
|
|
|
|
fdata[0] = uvs[tri_a[0]];
|
|
|
|
fdata[1] = uvs[tri_a[1]];
|
|
|
|
fdata[2] = uvs[tri_a[2]];
|
2015-02-10 23:40:26 +05:00
|
|
|
fdata += 3;
|
|
|
|
|
|
|
|
if(nverts[i] == 4) {
|
2016-01-20 09:13:04 +01:00
|
|
|
fdata[0] = uvs[tri_b[0]];
|
2016-01-20 14:54:57 +01:00
|
|
|
fdata[1] = uvs[tri_b[1]];
|
|
|
|
fdata[2] = uvs[tri_b[2]];
|
2015-02-10 23:40:26 +05:00
|
|
|
fdata += 3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* UV tangent */
|
2017-08-25 22:26:04 +02:00
|
|
|
if(need_tangent) {
|
|
|
|
AttributeStandard sign_std =
|
|
|
|
(active_render)? ATTR_STD_UV_TANGENT_SIGN
|
|
|
|
: ATTR_STD_NONE;
|
|
|
|
ustring sign_name = ustring(
|
|
|
|
(string(l->name().c_str()) + ".tangent_sign").c_str());
|
|
|
|
bool need_sign = (mesh->need_attribute(scene, sign_name) ||
|
|
|
|
mesh->need_attribute(scene, sign_std));
|
2016-01-20 09:13:04 +01:00
|
|
|
mikk_compute_tangents(b_mesh,
|
2018-01-22 14:28:43 +01:00
|
|
|
l->name().c_str(),
|
2016-01-20 09:13:04 +01:00
|
|
|
mesh,
|
|
|
|
need_sign,
|
|
|
|
active_render);
|
2015-02-10 23:40:26 +05:00
|
|
|
}
|
2017-08-25 22:26:04 +02:00
|
|
|
/* Remove temporarily created UV attribute. */
|
|
|
|
if(!need_uv && uv_attr != NULL) {
|
|
|
|
mesh->attributes.remove(uv_attr);
|
|
|
|
}
|
2015-02-10 23:40:26 +05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(mesh->need_attribute(scene, ATTR_STD_UV_TANGENT)) {
|
|
|
|
bool need_sign = mesh->need_attribute(scene, ATTR_STD_UV_TANGENT_SIGN);
|
2017-08-25 22:26:04 +02:00
|
|
|
mikk_compute_tangents(b_mesh, NULL, mesh, need_sign, true);
|
|
|
|
if(!mesh->need_attribute(scene, ATTR_STD_GENERATED)) {
|
|
|
|
mesh->attributes.remove(ATTR_STD_GENERATED);
|
|
|
|
}
|
2015-02-10 23:40:26 +05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-22 14:28:43 +01:00
|
|
|
static void attr_create_subd_uv_map(Scene *scene,
|
|
|
|
Mesh *mesh,
|
|
|
|
BL::Mesh& b_mesh,
|
|
|
|
bool subdivide_uvs)
|
|
|
|
{
|
|
|
|
if(b_mesh.uv_layers.length() != 0) {
|
|
|
|
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 = l->active_render();
|
|
|
|
AttributeStandard uv_std = (active_render)? ATTR_STD_UV: ATTR_STD_NONE;
|
|
|
|
ustring uv_name = ustring(l->name().c_str());
|
|
|
|
AttributeStandard tangent_std = (active_render)? ATTR_STD_UV_TANGENT
|
|
|
|
: ATTR_STD_NONE;
|
|
|
|
ustring tangent_name = ustring(
|
|
|
|
(string(l->name().c_str()) + ".tangent").c_str());
|
|
|
|
|
|
|
|
/* Denotes whether UV map was requested directly. */
|
|
|
|
const bool need_uv = mesh->need_attribute(scene, uv_name) ||
|
|
|
|
mesh->need_attribute(scene, uv_std);
|
|
|
|
/* Denotes whether tangent was requested directly. */
|
|
|
|
const bool need_tangent =
|
|
|
|
mesh->need_attribute(scene, tangent_name) ||
|
|
|
|
(active_render && mesh->need_attribute(scene, tangent_std));
|
|
|
|
|
|
|
|
Attribute *uv_attr = NULL;
|
|
|
|
|
|
|
|
/* UV map */
|
|
|
|
if(need_uv || need_tangent) {
|
|
|
|
if(active_render)
|
|
|
|
uv_attr = mesh->subd_attributes.add(uv_std, uv_name);
|
|
|
|
else
|
|
|
|
uv_attr = mesh->subd_attributes.add(uv_name, TypeDesc::TypePoint, ATTR_ELEMENT_CORNER);
|
|
|
|
|
|
|
|
if(subdivide_uvs) {
|
|
|
|
uv_attr->flags |= ATTR_SUBDIVIDED;
|
|
|
|
}
|
|
|
|
|
|
|
|
BL::Mesh::polygons_iterator p;
|
|
|
|
float3 *fdata = uv_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());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* UV tangent */
|
|
|
|
if(need_tangent) {
|
|
|
|
AttributeStandard sign_std =
|
|
|
|
(active_render)? ATTR_STD_UV_TANGENT_SIGN
|
|
|
|
: ATTR_STD_NONE;
|
|
|
|
ustring sign_name = ustring(
|
|
|
|
(string(l->name().c_str()) + ".tangent_sign").c_str());
|
|
|
|
bool need_sign = (mesh->need_attribute(scene, sign_name) ||
|
|
|
|
mesh->need_attribute(scene, sign_std));
|
|
|
|
mikk_compute_tangents(b_mesh,
|
|
|
|
l->name().c_str(),
|
|
|
|
mesh,
|
|
|
|
need_sign,
|
|
|
|
active_render);
|
|
|
|
}
|
|
|
|
/* Remove temporarily created UV attribute. */
|
|
|
|
if(!need_uv && uv_attr != NULL) {
|
|
|
|
mesh->subd_attributes.remove(uv_attr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(mesh->need_attribute(scene, ATTR_STD_UV_TANGENT)) {
|
|
|
|
bool need_sign = mesh->need_attribute(scene, ATTR_STD_UV_TANGENT_SIGN);
|
|
|
|
mikk_compute_tangents(b_mesh, NULL, mesh, need_sign, true);
|
|
|
|
if(!mesh->need_attribute(scene, ATTR_STD_GENERATED)) {
|
|
|
|
mesh->subd_attributes.remove(ATTR_STD_GENERATED);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-10 23:40:26 +05:00
|
|
|
/* Create vertex pointiness attributes. */
|
2017-02-13 12:00:10 +01:00
|
|
|
|
|
|
|
/* Compare vertices by sum of their coordinates. */
|
|
|
|
class VertexAverageComparator {
|
|
|
|
public:
|
|
|
|
VertexAverageComparator(const array<float3>& verts)
|
|
|
|
: verts_(verts) {
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator()(const int& vert_idx_a, const int& vert_idx_b)
|
|
|
|
{
|
|
|
|
const float3 &vert_a = verts_[vert_idx_a];
|
|
|
|
const float3 &vert_b = verts_[vert_idx_b];
|
|
|
|
if(vert_a == vert_b) {
|
|
|
|
/* Special case for doubles, so we ensure ordering. */
|
|
|
|
return vert_idx_a > vert_idx_b;
|
|
|
|
}
|
|
|
|
const float x1 = vert_a.x + vert_a.y + vert_a.z;
|
|
|
|
const float x2 = vert_b.x + vert_b.y + vert_b.z;
|
|
|
|
return x1 < x2;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
const array<float3>& verts_;
|
|
|
|
};
|
|
|
|
|
2015-02-10 23:40:26 +05:00
|
|
|
static void attr_create_pointiness(Scene *scene,
|
|
|
|
Mesh *mesh,
|
2016-07-16 19:42:28 -04:00
|
|
|
BL::Mesh& b_mesh,
|
|
|
|
bool subdivision)
|
2015-02-10 23:40:26 +05:00
|
|
|
{
|
2017-02-10 10:10:06 +01:00
|
|
|
if(!mesh->need_attribute(scene, ATTR_STD_POINTINESS)) {
|
|
|
|
return;
|
|
|
|
}
|
2017-02-10 13:23:40 +01:00
|
|
|
const int num_verts = b_mesh.vertices.length();
|
2017-04-07 15:07:25 +02:00
|
|
|
if(num_verts == 0) {
|
|
|
|
return;
|
|
|
|
}
|
2017-02-10 13:23:40 +01:00
|
|
|
/* STEP 1: Find out duplicated vertices and point duplicates to a single
|
|
|
|
* original vertex.
|
|
|
|
*/
|
2017-02-13 12:00:10 +01:00
|
|
|
vector<int> sorted_vert_indeices(num_verts);
|
2017-02-15 20:33:49 +01:00
|
|
|
for(int vert_index = 0; vert_index < num_verts; ++vert_index) {
|
2017-02-13 12:00:10 +01:00
|
|
|
sorted_vert_indeices[vert_index] = vert_index;
|
|
|
|
}
|
|
|
|
VertexAverageComparator compare(mesh->verts);
|
|
|
|
sort(sorted_vert_indeices.begin(), sorted_vert_indeices.end(), compare);
|
2017-02-10 13:23:40 +01:00
|
|
|
/* This array stores index of the original vertex for the given vertex
|
|
|
|
* index.
|
|
|
|
*/
|
|
|
|
vector<int> vert_orig_index(num_verts);
|
2017-02-15 20:33:49 +01:00
|
|
|
for(int sorted_vert_index = 0;
|
|
|
|
sorted_vert_index < num_verts;
|
|
|
|
++sorted_vert_index)
|
2017-02-13 12:00:10 +01:00
|
|
|
{
|
|
|
|
const int vert_index = sorted_vert_indeices[sorted_vert_index];
|
2017-02-13 10:40:05 +01:00
|
|
|
const float3 &vert_co = mesh->verts[vert_index];
|
2017-02-10 13:23:40 +01:00
|
|
|
bool found = false;
|
2017-02-13 12:00:10 +01:00
|
|
|
for(int other_sorted_vert_index = sorted_vert_index + 1;
|
|
|
|
other_sorted_vert_index < num_verts;
|
|
|
|
++other_sorted_vert_index)
|
2017-02-10 13:23:40 +01:00
|
|
|
{
|
2017-02-13 12:00:10 +01:00
|
|
|
const int other_vert_index =
|
|
|
|
sorted_vert_indeices[other_sorted_vert_index];
|
2017-02-13 10:40:05 +01:00
|
|
|
const float3 &other_vert_co = mesh->verts[other_vert_index];
|
2017-02-13 12:00:10 +01:00
|
|
|
/* We are too far away now, we wouldn't have duplicate. */
|
2017-03-10 15:34:54 +01:00
|
|
|
if((other_vert_co.x + other_vert_co.y + other_vert_co.z) -
|
|
|
|
(vert_co.x + vert_co.y + vert_co.z) > 3 * FLT_EPSILON)
|
2017-02-13 12:00:10 +01:00
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* Found duplicate. */
|
2017-02-15 12:39:06 +01:00
|
|
|
if(len_squared(other_vert_co - vert_co) < FLT_EPSILON) {
|
2017-02-10 13:23:40 +01:00
|
|
|
found = true;
|
2017-02-13 12:00:10 +01:00
|
|
|
vert_orig_index[vert_index] = other_vert_index;
|
2017-02-10 13:23:40 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2017-02-13 12:00:10 +01:00
|
|
|
if(!found) {
|
2017-02-10 13:23:40 +01:00
|
|
|
vert_orig_index[vert_index] = vert_index;
|
|
|
|
}
|
|
|
|
}
|
2017-02-13 12:00:10 +01:00
|
|
|
/* Make sure we always points to the very first orig vertex. */
|
|
|
|
for(int vert_index = 0; vert_index < num_verts; ++vert_index) {
|
|
|
|
int orig_index = vert_orig_index[vert_index];
|
|
|
|
while(orig_index != vert_orig_index[orig_index]) {
|
|
|
|
orig_index = vert_orig_index[orig_index];
|
|
|
|
}
|
|
|
|
vert_orig_index[vert_index] = orig_index;
|
|
|
|
}
|
|
|
|
sorted_vert_indeices.free_memory();
|
2017-02-10 13:23:40 +01:00
|
|
|
/* STEP 2: Calculate vertex normals taking into account their possible
|
|
|
|
* duplicates which gets "welded" together.
|
|
|
|
*/
|
|
|
|
vector<float3> vert_normal(num_verts, make_float3(0.0f, 0.0f, 0.0f));
|
|
|
|
/* First we accumulate all vertex normals in the original index. */
|
2017-02-13 10:40:05 +01:00
|
|
|
for(int vert_index = 0; vert_index < num_verts; ++vert_index) {
|
2017-02-10 13:23:40 +01:00
|
|
|
const float3 normal = get_float3(b_mesh.vertices[vert_index].normal());
|
|
|
|
const int orig_index = vert_orig_index[vert_index];
|
|
|
|
vert_normal[orig_index] += normal;
|
|
|
|
}
|
|
|
|
/* Then we normalize the accumulated result and flush it to all duplicates
|
|
|
|
* as well.
|
|
|
|
*/
|
2017-02-13 10:40:05 +01:00
|
|
|
for(int vert_index = 0; vert_index < num_verts; ++vert_index) {
|
2017-02-10 13:23:40 +01:00
|
|
|
const int orig_index = vert_orig_index[vert_index];
|
|
|
|
vert_normal[vert_index] = normalize(vert_normal[orig_index]);
|
|
|
|
}
|
|
|
|
/* STEP 3: Calculate pointiness using single ring neighborhood. */
|
|
|
|
vector<int> counter(num_verts, 0);
|
|
|
|
vector<float> raw_data(num_verts, 0.0f);
|
|
|
|
vector<float3> edge_accum(num_verts, make_float3(0.0f, 0.0f, 0.0f));
|
2017-02-10 10:10:06 +01:00
|
|
|
BL::Mesh::edges_iterator e;
|
2017-02-10 13:31:59 +01:00
|
|
|
EdgeMap visited_edges;
|
2017-02-10 13:23:40 +01:00
|
|
|
int edge_index = 0;
|
|
|
|
memset(&counter[0], 0, sizeof(int) * counter.size());
|
|
|
|
for(b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e, ++edge_index) {
|
|
|
|
const int v0 = vert_orig_index[b_mesh.edges[edge_index].vertices()[0]],
|
|
|
|
v1 = vert_orig_index[b_mesh.edges[edge_index].vertices()[1]];
|
2017-02-10 13:31:59 +01:00
|
|
|
if(visited_edges.exists(v0, v1)) {
|
2017-02-10 13:23:40 +01:00
|
|
|
continue;
|
|
|
|
}
|
2017-02-10 13:31:59 +01:00
|
|
|
visited_edges.insert(v0, v1);
|
2017-02-10 10:10:06 +01:00
|
|
|
float3 co0 = get_float3(b_mesh.vertices[v0].co()),
|
|
|
|
co1 = get_float3(b_mesh.vertices[v1].co());
|
|
|
|
float3 edge = normalize(co1 - co0);
|
|
|
|
edge_accum[v0] += edge;
|
|
|
|
edge_accum[v1] += -edge;
|
|
|
|
++counter[v0];
|
|
|
|
++counter[v1];
|
|
|
|
}
|
2017-02-13 10:40:05 +01:00
|
|
|
for(int vert_index = 0; vert_index < num_verts; ++vert_index) {
|
2017-02-10 13:23:40 +01:00
|
|
|
const int orig_index = vert_orig_index[vert_index];
|
|
|
|
if(orig_index != vert_index) {
|
|
|
|
/* Skip duplicates, they'll be overwritten later on. */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if(counter[vert_index] > 0) {
|
|
|
|
const float3 normal = vert_normal[vert_index];
|
|
|
|
const float angle =
|
|
|
|
safe_acosf(dot(normal,
|
|
|
|
edge_accum[vert_index] / counter[vert_index]));
|
|
|
|
raw_data[vert_index] = angle * M_1_PI_F;
|
2015-02-10 23:40:26 +05:00
|
|
|
}
|
2017-02-10 10:10:06 +01:00
|
|
|
else {
|
2017-02-10 13:23:40 +01:00
|
|
|
raw_data[vert_index] = 0.0f;
|
2015-02-10 23:40:26 +05:00
|
|
|
}
|
|
|
|
}
|
2017-02-10 13:23:40 +01:00
|
|
|
/* STEP 3: Blur vertices to approximate 2 ring neighborhood. */
|
2017-02-13 12:00:10 +01:00
|
|
|
AttributeSet& attributes = (subdivision)? mesh->subd_attributes: mesh->attributes;
|
|
|
|
Attribute *attr = attributes.add(ATTR_STD_POINTINESS);
|
|
|
|
float *data = attr->data_float();
|
2017-02-10 10:10:06 +01:00
|
|
|
memcpy(data, &raw_data[0], sizeof(float) * raw_data.size());
|
2017-02-10 13:23:40 +01:00
|
|
|
memset(&counter[0], 0, sizeof(int) * counter.size());
|
|
|
|
edge_index = 0;
|
|
|
|
visited_edges.clear();
|
|
|
|
for(b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e, ++edge_index) {
|
|
|
|
const int v0 = vert_orig_index[b_mesh.edges[edge_index].vertices()[0]],
|
|
|
|
v1 = vert_orig_index[b_mesh.edges[edge_index].vertices()[1]];
|
2017-02-10 13:31:59 +01:00
|
|
|
if(visited_edges.exists(v0, v1)) {
|
2017-02-10 13:23:40 +01:00
|
|
|
continue;
|
|
|
|
}
|
2017-02-10 13:31:59 +01:00
|
|
|
visited_edges.insert(v0, v1);
|
2017-02-10 10:10:06 +01:00
|
|
|
data[v0] += raw_data[v1];
|
|
|
|
data[v1] += raw_data[v0];
|
|
|
|
++counter[v0];
|
|
|
|
++counter[v1];
|
|
|
|
}
|
2017-02-13 10:40:05 +01:00
|
|
|
for(int vert_index = 0; vert_index < num_verts; ++vert_index) {
|
2017-02-10 13:23:40 +01:00
|
|
|
data[vert_index] /= counter[vert_index] + 1;
|
|
|
|
}
|
|
|
|
/* STEP 4: Copy attribute to the duplicated vertices. */
|
2017-02-13 10:40:05 +01:00
|
|
|
for(int vert_index = 0; vert_index < num_verts; ++vert_index) {
|
2017-02-10 13:23:40 +01:00
|
|
|
const int orig_index = vert_orig_index[vert_index];
|
|
|
|
data[vert_index] = data[orig_index];
|
2017-02-10 10:10:06 +01:00
|
|
|
}
|
2015-02-10 23:40:26 +05:00
|
|
|
}
|
|
|
|
|
2012-11-03 15:36:02 +00:00
|
|
|
/* Create Mesh */
|
|
|
|
|
2016-01-30 14:18:29 +01:00
|
|
|
static void create_mesh(Scene *scene,
|
|
|
|
Mesh *mesh,
|
|
|
|
BL::Mesh& b_mesh,
|
2016-07-16 19:42:28 -04:00
|
|
|
const vector<Shader*>& used_shaders,
|
2017-01-11 15:16:22 +01:00
|
|
|
bool subdivision = false,
|
|
|
|
bool subdivide_uvs = true)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2013-07-14 12:51:41 +00:00
|
|
|
/* count vertices and faces */
|
|
|
|
int numverts = b_mesh.vertices.length();
|
2016-07-16 19:42:28 -04:00
|
|
|
int numfaces = (!subdivision) ? b_mesh.tessfaces.length() : b_mesh.polygons.length();
|
2013-07-14 12:51:41 +00:00
|
|
|
int numtris = 0;
|
2016-07-16 19:42:28 -04:00
|
|
|
int numcorners = 0;
|
|
|
|
int numngons = 0;
|
2016-09-18 13:21:29 -04:00
|
|
|
bool use_loop_normals = b_mesh.use_auto_smooth() && (mesh->subdivision_type != Mesh::SUBDIVISION_CATMULL_CLARK);
|
2013-07-14 12:51:41 +00:00
|
|
|
|
2017-09-29 03:56:14 +02:00
|
|
|
/* If no faces, create empty mesh. */
|
|
|
|
if(numfaces == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
BL::Mesh::vertices_iterator v;
|
2013-07-14 12:51:41 +00:00
|
|
|
BL::Mesh::tessfaces_iterator f;
|
2016-07-16 19:42:28 -04:00
|
|
|
BL::Mesh::polygons_iterator p;
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-07-16 19:42:28 -04:00
|
|
|
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();
|
|
|
|
}
|
2013-07-14 12:51:41 +00:00
|
|
|
}
|
|
|
|
|
2016-05-08 00:09:08 +02:00
|
|
|
/* allocate memory */
|
|
|
|
mesh->reserve_mesh(numverts, numtris);
|
2016-07-16 19:42:28 -04:00
|
|
|
mesh->reserve_subd_faces(numfaces, numngons, numcorners);
|
2013-07-14 12:51:41 +00:00
|
|
|
|
|
|
|
/* create vertex coordinates and normals */
|
2016-05-08 00:09:08 +02:00
|
|
|
for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v)
|
|
|
|
mesh->add_vertex(get_float3(v->co()));
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-07-16 19:42:28 -04:00
|
|
|
AttributeSet& attributes = (subdivision)? mesh->subd_attributes: mesh->attributes;
|
|
|
|
Attribute *attr_N = attributes.add(ATTR_STD_VERTEX_NORMAL);
|
2011-10-16 17:00:48 +00:00
|
|
|
float3 *N = attr_N->data_float3();
|
|
|
|
|
|
|
|
for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v, ++N)
|
2012-06-09 18:56:12 +00:00
|
|
|
*N = get_float3(v->normal());
|
2014-04-15 08:29:22 +02:00
|
|
|
N = attr_N->data_float3();
|
2011-10-16 17:00:48 +00:00
|
|
|
|
2014-04-13 12:51:06 +02:00
|
|
|
/* create generated coordinates from undeformed coordinates */
|
2017-08-25 22:26:04 +02:00
|
|
|
const bool need_default_tangent =
|
|
|
|
(subdivision == false) &&
|
|
|
|
(b_mesh.tessface_uv_textures.length() == 0) &&
|
|
|
|
(mesh->need_attribute(scene, ATTR_STD_UV_TANGENT));
|
|
|
|
if(mesh->need_attribute(scene, ATTR_STD_GENERATED) ||
|
|
|
|
need_default_tangent)
|
|
|
|
{
|
2016-07-16 19:42:28 -04:00
|
|
|
Attribute *attr = attributes.add(ATTR_STD_GENERATED);
|
2016-07-16 22:57:06 -04:00
|
|
|
attr->flags |= ATTR_SUBDIVIDED;
|
2014-04-13 12:51:06 +02:00
|
|
|
|
|
|
|
float3 loc, size;
|
|
|
|
mesh_texture_space(b_mesh, loc, size);
|
|
|
|
|
|
|
|
float3 *generated = attr->data_float3();
|
|
|
|
size_t i = 0;
|
|
|
|
|
2017-08-25 22:26:04 +02:00
|
|
|
for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v) {
|
2014-04-13 12:51:06 +02:00
|
|
|
generated[i++] = get_float3(v->undeformed_co())*size - loc;
|
2017-08-25 22:26:04 +02:00
|
|
|
}
|
2014-04-13 12:51:06 +02:00
|
|
|
}
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* create faces */
|
2013-07-14 12:51:41 +00:00
|
|
|
vector<int> nverts(numfaces);
|
2016-01-20 09:13:04 +01:00
|
|
|
vector<int> face_flags(numfaces, FACE_FLAG_NONE);
|
2016-05-08 00:09:08 +02:00
|
|
|
int fi = 0;
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-07-16 19:42:28 -04:00
|
|
|
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;
|
|
|
|
|
2017-02-22 10:53:28 +01:00
|
|
|
if(use_loop_normals) {
|
|
|
|
BL::Array<float, 12> loop_normals = f->split_normals();
|
|
|
|
for(int i = 0; i < n; i++) {
|
|
|
|
N[vi[i]] = make_float3(loop_normals[i * 3],
|
|
|
|
loop_normals[i * 3 + 1],
|
|
|
|
loop_normals[i * 3 + 2]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-11 16:32:57 +01:00
|
|
|
/* Create triangles.
|
2016-07-16 19:42:28 -04:00
|
|
|
*
|
2017-01-11 16:32:57 +01:00
|
|
|
* NOTE: Autosmooth is already taken care about.
|
|
|
|
*/
|
2016-07-16 19:42:28 -04:00
|
|
|
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;
|
|
|
|
}
|
2013-01-01 19:44:09 +00:00
|
|
|
}
|
|
|
|
else {
|
2016-07-16 19:42:28 -04:00
|
|
|
mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth);
|
2013-01-01 19:44:09 +00:00
|
|
|
}
|
2016-07-16 19:42:28 -04:00
|
|
|
|
|
|
|
nverts[fi] = n;
|
2013-01-01 19:44:09 +00:00
|
|
|
}
|
2016-07-16 19:42:28 -04:00
|
|
|
}
|
|
|
|
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;
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2017-03-21 04:30:08 +01:00
|
|
|
vi.resize(n);
|
2016-07-16 19:42:28 -04:00
|
|
|
for(int i = 0; i < n; i++) {
|
2017-01-11 16:32:57 +01:00
|
|
|
/* NOTE: Autosmooth is already taken care about. */
|
2016-07-16 19:42:28 -04:00
|
|
|
vi[i] = b_mesh.loops[p->loop_start() + i].vertex_index();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* create subd faces */
|
|
|
|
mesh->add_subd_face(&vi[0], n, shader, smooth);
|
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
2015-02-10 23:40:26 +05:00
|
|
|
/* Create all needed attributes.
|
|
|
|
* The calculate functions will check whether they're needed or not.
|
2015-02-06 12:35:46 +05:00
|
|
|
*/
|
2017-02-10 10:06:58 +01:00
|
|
|
attr_create_pointiness(scene, mesh, b_mesh, subdivision);
|
2016-07-16 19:42:28 -04:00
|
|
|
attr_create_vertex_color(scene, mesh, b_mesh, nverts, face_flags, subdivision);
|
2018-01-22 14:28:43 +01:00
|
|
|
|
|
|
|
if(subdivision) {
|
2018-01-22 10:59:14 +01:00
|
|
|
attr_create_subd_uv_map(scene, mesh, b_mesh, subdivide_uvs);
|
2018-01-22 14:28:43 +01:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
attr_create_uv_map(scene, mesh, b_mesh, nverts, face_flags);
|
|
|
|
}
|
2012-10-10 14:21:58 +00:00
|
|
|
|
2013-12-31 17:33:55 +01:00
|
|
|
/* for volume objects, create a matrix to transform from object space to
|
|
|
|
* mesh texture space. this does not work with deformations but that can
|
|
|
|
* probably only be done well with a volume grid mapping of coordinates */
|
|
|
|
if(mesh->need_attribute(scene, ATTR_STD_GENERATED_TRANSFORM)) {
|
|
|
|
Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED_TRANSFORM);
|
|
|
|
Transform *tfm = attr->data_transform();
|
|
|
|
|
|
|
|
float3 loc, size;
|
|
|
|
mesh_texture_space(b_mesh, loc, size);
|
|
|
|
|
|
|
|
*tfm = transform_translate(-loc)*transform_scale(size);
|
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
2016-01-30 14:18:29 +01:00
|
|
|
static void create_subd_mesh(Scene *scene,
|
|
|
|
Mesh *mesh,
|
2016-04-25 10:04:06 +02:00
|
|
|
BL::Object& b_ob,
|
2016-01-30 14:18:29 +01:00
|
|
|
BL::Mesh& b_mesh,
|
2016-05-14 14:50:03 +02:00
|
|
|
const vector<Shader*>& used_shaders,
|
2016-04-18 22:35:49 +02:00
|
|
|
float dicing_rate,
|
|
|
|
int max_subdivisions)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2016-07-16 22:57:06 -04:00
|
|
|
BL::SubsurfModifier subsurf_mod(b_ob.modifiers[b_ob.modifiers.length()-1]);
|
|
|
|
bool subdivide_uvs = subsurf_mod.use_subsurf_uv();
|
|
|
|
|
|
|
|
create_mesh(scene, mesh, b_mesh, used_shaders, true, subdivide_uvs);
|
|
|
|
|
|
|
|
/* export creases */
|
|
|
|
size_t num_creases = 0;
|
|
|
|
BL::Mesh::edges_iterator e;
|
|
|
|
|
|
|
|
for(b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e) {
|
|
|
|
if(e->crease() != 0.0f) {
|
|
|
|
num_creases++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mesh->subd_creases.resize(num_creases);
|
|
|
|
|
|
|
|
Mesh::SubdEdgeCrease* crease = mesh->subd_creases.data();
|
|
|
|
for(b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e) {
|
|
|
|
if(e->crease() != 0.0f) {
|
|
|
|
crease->v[0] = e->vertices()[0];
|
|
|
|
crease->v[1] = e->vertices()[1];
|
|
|
|
crease->crease = e->crease();
|
|
|
|
|
|
|
|
crease++;
|
|
|
|
}
|
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-07-16 22:57:06 -04:00
|
|
|
/* set subd params */
|
2016-08-14 12:41:45 -04:00
|
|
|
if(!mesh->subd_params) {
|
|
|
|
mesh->subd_params = new SubdParams(mesh);
|
|
|
|
}
|
|
|
|
SubdParams& sdparams = *mesh->subd_params;
|
2016-07-16 19:56:45 -04:00
|
|
|
|
|
|
|
PointerRNA cobj = RNA_pointer_get(&b_ob.ptr, "cycles");
|
|
|
|
|
|
|
|
sdparams.dicing_rate = max(0.1f, RNA_float_get(&cobj, "dicing_rate") * dicing_rate);
|
2016-04-18 22:35:49 +02:00
|
|
|
sdparams.max_level = max_subdivisions;
|
2016-04-11 22:49:09 +02:00
|
|
|
|
2018-01-12 20:22:55 +01:00
|
|
|
scene->dicing_camera->update(scene);
|
2018-01-12 00:50:34 +01:00
|
|
|
sdparams.camera = scene->dicing_camera;
|
2016-04-11 22:49:09 +02:00
|
|
|
sdparams.objecttoworld = get_transform(b_ob.matrix_world());
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Sync */
|
|
|
|
|
2016-07-16 18:56:59 +02:00
|
|
|
static void sync_mesh_fluid_motion(BL::Object& b_ob, Scene *scene, Mesh *mesh)
|
|
|
|
{
|
|
|
|
if(scene->need_motion() == Scene::MOTION_NONE)
|
|
|
|
return;
|
|
|
|
|
|
|
|
BL::DomainFluidSettings b_fluid_domain = object_fluid_domain_find(b_ob);
|
|
|
|
|
|
|
|
if(!b_fluid_domain)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* If the mesh has modifiers following the fluid domain we can't export motion. */
|
|
|
|
if(b_fluid_domain.fluid_mesh_vertices.length() != mesh->verts.size())
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Find or add attribute */
|
|
|
|
float3 *P = &mesh->verts[0];
|
|
|
|
Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
|
|
|
|
|
|
|
|
if(!attr_mP) {
|
|
|
|
attr_mP = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Only export previous and next frame, we don't have any in between data. */
|
|
|
|
float motion_times[2] = {-1.0f, 1.0f};
|
2016-10-24 12:26:12 +02:00
|
|
|
for(int step = 0; step < 2; step++) {
|
2016-07-16 18:56:59 +02:00
|
|
|
float relative_time = motion_times[step] * scene->motion_shutter_time() * 0.5f;
|
|
|
|
float3 *mP = attr_mP->data_float3() + step*mesh->verts.size();
|
|
|
|
|
|
|
|
BL::DomainFluidSettings::fluid_mesh_vertices_iterator fvi;
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
for(b_fluid_domain.fluid_mesh_vertices.begin(fvi); fvi != b_fluid_domain.fluid_mesh_vertices.end(); ++fvi, ++i) {
|
|
|
|
mP[i] = P[i] + get_float3(fvi->velocity()) * relative_time;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-26 16:46:48 +01:00
|
|
|
Mesh *BlenderSync::sync_mesh(BL::Depsgraph& b_depsgraph,
|
|
|
|
BL::Object& b_ob,
|
2017-06-06 16:27:02 +02:00
|
|
|
BL::Object& b_ob_instance,
|
2016-01-30 14:18:29 +01:00
|
|
|
bool object_updated,
|
|
|
|
bool hide_tris)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
/* test if we can instance or if the object is modified */
|
|
|
|
BL::ID b_ob_data = b_ob.data();
|
2017-06-06 16:27:02 +02:00
|
|
|
BL::ID key = (BKE_object_is_modified(b_ob))? b_ob_instance: b_ob_data;
|
2017-11-22 10:52:39 -02:00
|
|
|
BL::Material material_override = view_layer.material_override;
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
/* find shader indices */
|
2016-05-14 14:50:03 +02:00
|
|
|
vector<Shader*> used_shaders;
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
BL::Object::material_slots_iterator slot;
|
2011-09-12 13:13:56 +00:00
|
|
|
for(b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot) {
|
2016-01-30 14:18:29 +01:00
|
|
|
if(material_override) {
|
2011-12-21 20:51:55 +00:00
|
|
|
find_shader(material_override, used_shaders, scene->default_surface);
|
2016-01-30 14:18:29 +01:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
BL::ID b_material(slot->material());
|
|
|
|
find_shader(b_material, used_shaders, scene->default_surface);
|
|
|
|
}
|
2011-09-12 13:13:56 +00:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2012-04-11 08:57:54 +00:00
|
|
|
if(used_shaders.size() == 0) {
|
2012-05-02 09:33:45 +00:00
|
|
|
if(material_override)
|
2012-04-23 18:15:38 +00:00
|
|
|
find_shader(material_override, used_shaders, scene->default_surface);
|
2012-04-11 08:57:54 +00:00
|
|
|
else
|
|
|
|
used_shaders.push_back(scene->default_surface);
|
|
|
|
}
|
2017-05-30 09:43:43 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* test if we need to sync */
|
2015-04-09 21:21:48 +05:00
|
|
|
int requested_geometry_flags = Mesh::GEOMETRY_NONE;
|
2017-11-22 10:52:39 -02:00
|
|
|
if(view_layer.use_surfaces) {
|
2015-04-09 21:21:48 +05:00
|
|
|
requested_geometry_flags |= Mesh::GEOMETRY_TRIANGLES;
|
|
|
|
}
|
2017-11-22 10:52:39 -02:00
|
|
|
if(view_layer.use_hair) {
|
2015-04-09 21:21:48 +05:00
|
|
|
requested_geometry_flags |= Mesh::GEOMETRY_CURVES;
|
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
Mesh *mesh;
|
|
|
|
|
|
|
|
if(!mesh_map.sync(&mesh, key)) {
|
|
|
|
/* if transform was applied to mesh, need full update */
|
|
|
|
if(object_updated && mesh->transform_applied);
|
|
|
|
/* test if shaders changed, these can be object level so mesh
|
2012-06-09 17:22:52 +00:00
|
|
|
* does not get tagged for recalc */
|
2011-04-27 11:58:34 +00:00
|
|
|
else if(mesh->used_shaders != used_shaders);
|
2015-04-09 21:21:48 +05:00
|
|
|
else if(requested_geometry_flags != mesh->geometry_flags);
|
2011-04-27 11:58:34 +00:00
|
|
|
else {
|
|
|
|
/* even if not tagged for recalc, we may need to sync anyway
|
|
|
|
* because the shader needs different mesh attributes */
|
|
|
|
bool attribute_recalc = false;
|
|
|
|
|
2016-05-14 14:50:03 +02:00
|
|
|
foreach(Shader *shader, mesh->used_shaders)
|
2018-01-24 20:19:48 +01:00
|
|
|
if(shader->need_update_mesh)
|
2011-04-27 11:58:34 +00:00
|
|
|
attribute_recalc = true;
|
|
|
|
|
|
|
|
if(!attribute_recalc)
|
|
|
|
return mesh;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-31 10:57:43 +00:00
|
|
|
/* ensure we only sync instanced meshes once */
|
|
|
|
if(mesh_synced.find(mesh) != mesh_synced.end())
|
|
|
|
return mesh;
|
2017-05-30 09:43:43 +02:00
|
|
|
|
2011-05-31 10:57:43 +00:00
|
|
|
mesh_synced.insert(mesh);
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* create derived mesh */
|
2018-01-25 16:11:06 +01:00
|
|
|
array<int> oldtriangles;
|
|
|
|
array<Mesh::SubdFace> oldsubd_faces;
|
|
|
|
array<int> oldsubd_face_corners;
|
|
|
|
oldtriangles.steal_data(mesh->triangles);
|
|
|
|
oldsubd_faces.steal_data(mesh->subd_faces);
|
|
|
|
oldsubd_face_corners.steal_data(mesh->subd_face_corners);
|
2017-05-30 09:43:43 +02:00
|
|
|
|
2013-05-10 13:34:49 +00:00
|
|
|
/* compares curve_keys rather than strands in order to handle quick hair
|
2014-08-13 08:38:16 +10:00
|
|
|
* adjustments in dynamic BVH - other methods could probably do this better*/
|
2018-01-25 16:11:06 +01:00
|
|
|
array<float3> oldcurve_keys;
|
|
|
|
array<float> oldcurve_radius;
|
|
|
|
oldcurve_keys.steal_data(mesh->curve_keys);
|
|
|
|
oldcurve_radius.steal_data(mesh->curve_radius);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
mesh->clear();
|
|
|
|
mesh->used_shaders = used_shaders;
|
2011-10-03 15:31:45 +00:00
|
|
|
mesh->name = ustring(b_ob_data.name().c_str());
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2015-04-09 21:21:48 +05:00
|
|
|
if(requested_geometry_flags != Mesh::GEOMETRY_NONE) {
|
2014-07-31 20:18:51 +06:00
|
|
|
/* mesh objects does have special handle in the dependency graph,
|
|
|
|
* they're ensured to have properly updated.
|
|
|
|
*
|
|
|
|
* updating meshes here will end up having derived mesh referencing
|
|
|
|
* freed data from the blender side.
|
|
|
|
*/
|
|
|
|
if(preview && b_ob.type() != BL::Object::type_MESH)
|
2018-06-01 17:08:38 +02:00
|
|
|
b_ob.update_from_editmode(b_data);
|
2013-07-08 22:41:14 +00:00
|
|
|
|
2013-07-29 19:39:23 +00:00
|
|
|
bool need_undeformed = mesh->need_attribute(scene, ATTR_STD_GENERATED);
|
2016-07-16 19:56:45 -04:00
|
|
|
|
2016-09-18 12:04:12 -04:00
|
|
|
mesh->subdivision_type = object_subdivision_type(b_ob, preview, experimental);
|
2016-07-16 19:56:45 -04:00
|
|
|
|
2017-01-25 00:35:20 -05:00
|
|
|
/* Disable adaptive subdivision while baking as the baking system
|
|
|
|
* currently doesnt support the topology and will crash.
|
|
|
|
*/
|
|
|
|
if(scene->bake_manager->get_baking()) {
|
|
|
|
mesh->subdivision_type = Mesh::SUBDIVISION_NONE;
|
|
|
|
}
|
|
|
|
|
2017-01-11 16:23:54 +01:00
|
|
|
BL::Mesh b_mesh = object_to_mesh(b_data,
|
|
|
|
b_ob,
|
2018-04-08 09:28:52 +02:00
|
|
|
b_depsgraph,
|
2018-05-22 19:42:41 +02:00
|
|
|
false,
|
2017-01-11 16:23:54 +01:00
|
|
|
need_undeformed,
|
|
|
|
mesh->subdivision_type);
|
2012-12-28 14:21:30 +00:00
|
|
|
|
2013-05-10 13:34:49 +00:00
|
|
|
if(b_mesh) {
|
2017-11-22 10:52:39 -02:00
|
|
|
if(view_layer.use_surfaces && !hide_tris) {
|
2016-07-16 19:56:45 -04:00
|
|
|
if(mesh->subdivision_type != Mesh::SUBDIVISION_NONE)
|
2016-07-29 15:06:13 +02:00
|
|
|
create_subd_mesh(scene, mesh, b_ob, b_mesh, used_shaders,
|
2016-04-18 22:35:49 +02:00
|
|
|
dicing_rate, max_subdivisions);
|
2013-05-10 13:34:49 +00:00
|
|
|
else
|
2016-07-16 19:42:28 -04:00
|
|
|
create_mesh(scene, mesh, b_mesh, used_shaders, false);
|
2014-03-29 13:03:48 +01:00
|
|
|
|
2014-06-21 22:18:48 +02:00
|
|
|
create_mesh_volume_attributes(scene, b_ob, mesh, b_scene.frame_current());
|
2013-05-10 13:34:49 +00:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2017-11-22 10:52:39 -02:00
|
|
|
if(view_layer.use_hair && mesh->subdivision_type == Mesh::SUBDIVISION_NONE)
|
2018-04-08 09:28:52 +02:00
|
|
|
sync_curves(mesh, b_mesh, b_ob, false);
|
2013-05-10 13:34:49 +00:00
|
|
|
|
|
|
|
/* free derived mesh */
|
2017-09-13 20:12:19 +05:00
|
|
|
b_data.meshes.remove(b_mesh, false, true, false);
|
2013-05-10 13:34:49 +00:00
|
|
|
}
|
2011-05-31 11:12:42 +00:00
|
|
|
}
|
2015-04-09 21:21:48 +05:00
|
|
|
mesh->geometry_flags = requested_geometry_flags;
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-07-16 18:56:59 +02:00
|
|
|
/* fluid motion */
|
|
|
|
sync_mesh_fluid_motion(b_ob, scene, mesh);
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* tag update */
|
2018-01-25 16:11:06 +01:00
|
|
|
bool rebuild = (oldtriangles != mesh->triangles) ||
|
|
|
|
(oldsubd_faces != mesh->subd_faces) ||
|
|
|
|
(oldsubd_face_corners != mesh->subd_face_corners) ||
|
|
|
|
(oldcurve_keys != mesh->curve_keys) ||
|
|
|
|
(oldcurve_radius != mesh->curve_radius);
|
2017-05-30 09:43:43 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
mesh->tag_update(scene, rebuild);
|
|
|
|
|
|
|
|
return mesh;
|
|
|
|
}
|
|
|
|
|
2018-02-26 16:46:48 +01:00
|
|
|
void BlenderSync::sync_mesh_motion(BL::Depsgraph& b_depsgraph,
|
|
|
|
BL::Object& b_ob,
|
2016-01-30 14:18:29 +01:00
|
|
|
Object *object,
|
|
|
|
float motion_time)
|
2012-04-30 12:49:26 +00:00
|
|
|
{
|
2013-10-17 16:05:57 +00:00
|
|
|
/* ensure we only sync instanced meshes once */
|
2014-03-29 13:03:46 +01:00
|
|
|
Mesh *mesh = object->mesh;
|
|
|
|
|
2013-10-17 16:05:57 +00:00
|
|
|
if(mesh_motion_synced.find(mesh) != mesh_motion_synced.end())
|
|
|
|
return;
|
|
|
|
|
|
|
|
mesh_motion_synced.insert(mesh);
|
|
|
|
|
2014-05-12 18:36:01 +02:00
|
|
|
/* ensure we only motion sync meshes that also had mesh synced, to avoid
|
|
|
|
* unnecessary work and to ensure that its attributes were clear */
|
|
|
|
if(mesh_synced.find(mesh) == mesh_synced.end())
|
|
|
|
return;
|
|
|
|
|
2018-03-10 00:37:07 +01:00
|
|
|
/* Find time matching motion step required by mesh. */
|
|
|
|
int motion_step = mesh->motion_step(motion_time);
|
|
|
|
if(motion_step < 0) {
|
|
|
|
return;
|
2014-03-29 13:03:46 +01:00
|
|
|
}
|
|
|
|
|
2014-05-05 16:35:20 +02:00
|
|
|
/* skip empty meshes */
|
2017-04-07 12:48:43 +02:00
|
|
|
const size_t numverts = mesh->verts.size();
|
|
|
|
const size_t numkeys = mesh->curve_keys.size();
|
2014-03-29 13:03:46 +01:00
|
|
|
|
2014-05-05 16:35:20 +02:00
|
|
|
if(!numverts && !numkeys)
|
2014-03-29 13:03:46 +01:00
|
|
|
return;
|
2017-05-30 09:43:43 +02:00
|
|
|
|
2014-05-05 16:35:20 +02:00
|
|
|
/* skip objects without deforming modifiers. this is not totally reliable,
|
|
|
|
* would need a more extensive check to see which objects are animated */
|
|
|
|
BL::Mesh b_mesh(PointerRNA_NULL);
|
|
|
|
|
2016-07-16 18:56:59 +02:00
|
|
|
/* fluid motion is exported immediate with mesh, skip here */
|
|
|
|
BL::DomainFluidSettings b_fluid_domain = object_fluid_domain_find(b_ob);
|
2016-10-24 12:26:12 +02:00
|
|
|
if(b_fluid_domain)
|
2016-07-16 18:56:59 +02:00
|
|
|
return;
|
|
|
|
|
2014-05-05 16:35:20 +02:00
|
|
|
if(ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview)) {
|
|
|
|
/* get derived mesh */
|
2017-01-11 16:23:54 +01:00
|
|
|
b_mesh = object_to_mesh(b_data,
|
|
|
|
b_ob,
|
2018-04-08 09:28:52 +02:00
|
|
|
b_depsgraph,
|
2018-05-22 19:42:41 +02:00
|
|
|
false,
|
2017-01-11 16:23:54 +01:00
|
|
|
false,
|
|
|
|
Mesh::SUBDIVISION_NONE);
|
2014-05-05 16:35:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if(!b_mesh) {
|
|
|
|
/* if we have no motion blur on this frame, but on other frames, copy */
|
|
|
|
if(numverts) {
|
|
|
|
/* triangles */
|
|
|
|
Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
|
|
|
|
|
|
|
|
if(attr_mP) {
|
|
|
|
Attribute *attr_mN = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL);
|
|
|
|
Attribute *attr_N = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL);
|
|
|
|
float3 *P = &mesh->verts[0];
|
|
|
|
float3 *N = (attr_N)? attr_N->data_float3(): NULL;
|
|
|
|
|
2018-03-10 00:37:07 +01:00
|
|
|
memcpy(attr_mP->data_float3() + motion_step*numverts, P, sizeof(float3)*numverts);
|
2014-05-05 16:35:20 +02:00
|
|
|
if(attr_mN)
|
2018-03-10 00:37:07 +01:00
|
|
|
memcpy(attr_mN->data_float3() + motion_step*numverts, N, sizeof(float3)*numverts);
|
2014-05-05 16:35:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(numkeys) {
|
|
|
|
/* curves */
|
|
|
|
Attribute *attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
|
|
|
|
|
|
|
|
if(attr_mP) {
|
2016-05-08 00:09:08 +02:00
|
|
|
float3 *keys = &mesh->curve_keys[0];
|
2018-03-10 00:37:07 +01:00
|
|
|
memcpy(attr_mP->data_float3() + motion_step*numkeys, keys, sizeof(float3)*numkeys);
|
2014-05-05 16:35:20 +02:00
|
|
|
}
|
|
|
|
}
|
2012-04-30 12:49:26 +00:00
|
|
|
|
2014-03-29 13:03:46 +01:00
|
|
|
return;
|
2014-05-05 16:35:20 +02:00
|
|
|
}
|
|
|
|
|
2015-09-04 15:19:22 +05:00
|
|
|
/* TODO(sergey): Perform preliminary check for number of verticies. */
|
2014-03-29 13:03:46 +01:00
|
|
|
if(numverts) {
|
2017-04-07 12:48:43 +02:00
|
|
|
/* Find attributes. */
|
2014-03-29 13:03:46 +01:00
|
|
|
Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
|
2014-03-29 13:03:46 +01:00
|
|
|
Attribute *attr_mN = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL);
|
|
|
|
Attribute *attr_N = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL);
|
2014-03-29 13:03:46 +01:00
|
|
|
bool new_attribute = false;
|
2017-04-07 12:48:43 +02:00
|
|
|
/* Add new attributes if they don't exist already. */
|
2014-03-29 13:03:46 +01:00
|
|
|
if(!attr_mP) {
|
|
|
|
attr_mP = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
|
2014-03-29 13:03:46 +01:00
|
|
|
if(attr_N)
|
|
|
|
attr_mN = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_NORMAL);
|
2014-03-29 13:03:46 +01:00
|
|
|
|
|
|
|
new_attribute = true;
|
|
|
|
}
|
2017-04-07 12:48:43 +02:00
|
|
|
/* Load vertex data from mesh. */
|
2018-03-10 00:37:07 +01:00
|
|
|
float3 *mP = attr_mP->data_float3() + motion_step*numverts;
|
|
|
|
float3 *mN = (attr_mN)? attr_mN->data_float3() + motion_step*numverts: NULL;
|
2017-04-07 12:48:43 +02:00
|
|
|
/* NOTE: We don't copy more that existing amount of vertices to prevent
|
|
|
|
* possible memory corruption.
|
|
|
|
*/
|
2014-03-29 13:03:46 +01:00
|
|
|
BL::Mesh::vertices_iterator v;
|
|
|
|
int i = 0;
|
2014-03-29 13:03:46 +01:00
|
|
|
for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end() && i < numverts; ++v, ++i) {
|
2014-03-29 13:03:46 +01:00
|
|
|
mP[i] = get_float3(v->co());
|
2014-03-29 13:03:46 +01:00
|
|
|
if(mN)
|
|
|
|
mN[i] = get_float3(v->normal());
|
|
|
|
}
|
2014-03-29 13:03:46 +01:00
|
|
|
if(new_attribute) {
|
2017-04-07 12:48:43 +02:00
|
|
|
/* In case of new attribute, we verify if there really was any motion. */
|
2015-09-04 15:19:22 +05:00
|
|
|
if(b_mesh.vertices.length() != numverts ||
|
|
|
|
memcmp(mP, &mesh->verts[0], sizeof(float3)*numverts) == 0)
|
|
|
|
{
|
2014-03-29 13:03:46 +01:00
|
|
|
/* no motion, remove attributes again */
|
2016-04-26 16:17:11 +02:00
|
|
|
if(b_mesh.vertices.length() != numverts) {
|
2017-01-11 14:34:56 +01:00
|
|
|
VLOG(1) << "Topology differs, disabling motion blur for object "
|
|
|
|
<< b_ob.name();
|
2016-04-26 16:17:11 +02:00
|
|
|
}
|
|
|
|
else {
|
2017-01-11 14:34:56 +01:00
|
|
|
VLOG(1) << "No actual deformation motion for object "
|
|
|
|
<< b_ob.name();
|
2016-04-26 16:17:11 +02:00
|
|
|
}
|
2014-03-29 13:03:46 +01:00
|
|
|
mesh->attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION);
|
2014-03-29 13:03:46 +01:00
|
|
|
if(attr_mN)
|
|
|
|
mesh->attributes.remove(ATTR_STD_MOTION_VERTEX_NORMAL);
|
2014-03-29 13:03:46 +01:00
|
|
|
}
|
2018-03-10 00:37:07 +01:00
|
|
|
else if(motion_step > 0) {
|
2015-03-09 13:02:06 +05:00
|
|
|
VLOG(1) << "Filling deformation motion for object " << b_ob.name();
|
2014-03-29 13:03:46 +01:00
|
|
|
/* motion, fill up previous steps that we might have skipped because
|
|
|
|
* they had no motion, but we need them anyway now */
|
|
|
|
float3 *P = &mesh->verts[0];
|
2014-03-29 13:03:46 +01:00
|
|
|
float3 *N = (attr_N)? attr_N->data_float3(): NULL;
|
2018-03-10 00:37:07 +01:00
|
|
|
for(int step = 0; step < motion_step; step++) {
|
2014-03-29 13:03:46 +01:00
|
|
|
memcpy(attr_mP->data_float3() + step*numverts, P, sizeof(float3)*numverts);
|
2014-05-05 16:35:20 +02:00
|
|
|
if(attr_mN)
|
|
|
|
memcpy(attr_mN->data_float3() + step*numverts, N, sizeof(float3)*numverts);
|
2014-03-29 13:03:46 +01:00
|
|
|
}
|
2014-03-29 13:03:46 +01:00
|
|
|
}
|
|
|
|
}
|
2017-04-07 12:48:43 +02:00
|
|
|
else {
|
|
|
|
if(b_mesh.vertices.length() != numverts) {
|
|
|
|
VLOG(1) << "Topology differs, discarding motion blur for object "
|
2018-03-10 00:37:07 +01:00
|
|
|
<< b_ob.name() << " at time " << motion_step;
|
2017-04-07 12:48:43 +02:00
|
|
|
memcpy(mP, &mesh->verts[0], sizeof(float3)*numverts);
|
|
|
|
if(mN != NULL) {
|
|
|
|
memcpy(mN, attr_N->data_float3(), sizeof(float3)*numverts);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-04-30 12:49:26 +00:00
|
|
|
}
|
2014-03-29 13:03:46 +01:00
|
|
|
|
|
|
|
/* hair motion */
|
|
|
|
if(numkeys)
|
2018-04-08 09:28:52 +02:00
|
|
|
sync_curves(mesh, b_mesh, b_ob, true, motion_step);
|
2014-03-29 13:03:46 +01:00
|
|
|
|
|
|
|
/* free derived mesh */
|
2017-09-13 20:12:19 +05:00
|
|
|
b_data.meshes.remove(b_mesh, false, true, false);
|
2012-04-30 12:49:26 +00:00
|
|
|
}
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
CCL_NAMESPACE_END
|