Merge branch 'master' into greasepencil-object
This commit is contained in:
@@ -3,7 +3,9 @@
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/../../cmake/config/blender_release.cmake")
|
||||
|
||||
message(STATUS "Building in CentOS 7 64bit environment")
|
||||
|
||||
set(LIBDIR_NAME "linux_centos7_x86_64")
|
||||
set(WITH_CXX11_ABI OFF CACHE BOOL "" FORCE)
|
||||
|
||||
# Default to only build Blender
|
||||
set(WITH_BLENDER ON CACHE BOOL "" FORCE)
|
||||
|
@@ -102,6 +102,7 @@ using Alembic::AbcGeom::kFacevaryingScope;
|
||||
using Alembic::AbcGeom::kVaryingScope;
|
||||
using Alembic::AbcGeom::kVertexScope;
|
||||
using Alembic::AbcGeom::kWrapExisting;
|
||||
using Alembic::AbcGeom::N3fArraySample;
|
||||
using Alembic::AbcGeom::N3fArraySamplePtr;
|
||||
using Alembic::AbcGeom::UInt32ArraySample;
|
||||
|
||||
@@ -124,12 +125,13 @@ static void get_vertices(struct Mesh *mesh, std::vector<Imath::V3f> &points)
|
||||
static void get_topology(struct Mesh *mesh,
|
||||
std::vector<int32_t> &poly_verts,
|
||||
std::vector<int32_t> &loop_counts,
|
||||
bool &r_export_loop_normals)
|
||||
bool &r_has_flat_shaded_poly)
|
||||
{
|
||||
const int num_poly = mesh->totpoly;
|
||||
const int num_loops = mesh->totloop;
|
||||
MLoop *mloop = mesh->mloop;
|
||||
MPoly *mpoly = mesh->mpoly;
|
||||
r_has_flat_shaded_poly = false;
|
||||
|
||||
poly_verts.clear();
|
||||
loop_counts.clear();
|
||||
@@ -141,7 +143,7 @@ static void get_topology(struct Mesh *mesh,
|
||||
MPoly &poly = mpoly[i];
|
||||
loop_counts.push_back(poly.totloop);
|
||||
|
||||
r_export_loop_normals |= (poly.flag & ME_SMOOTH) != 0;
|
||||
r_has_flat_shaded_poly |= (poly.flag & ME_SMOOTH) == 0;
|
||||
|
||||
MLoop *loop = mloop + poly.loopstart + (poly.totloop - 1);
|
||||
|
||||
@@ -177,66 +179,31 @@ static void get_creases(struct Mesh *mesh,
|
||||
lengths.resize(sharpnesses.size(), 2);
|
||||
}
|
||||
|
||||
static void get_vertex_normals(struct Mesh *mesh, std::vector<Imath::V3f> &normals)
|
||||
static void get_loop_normals(struct Mesh *mesh,
|
||||
std::vector<Imath::V3f> &normals,
|
||||
bool has_flat_shaded_poly)
|
||||
{
|
||||
normals.clear();
|
||||
normals.resize(mesh->totvert);
|
||||
|
||||
MVert *verts = mesh->mvert;
|
||||
float no[3];
|
||||
|
||||
for (int i = 0, e = mesh->totvert; i < e; i++) {
|
||||
normal_short_to_float_v3(no, verts[i].no);
|
||||
copy_yup_from_zup(normals[i].getValue(), no);
|
||||
/* If all polygons are smooth shaded, and there are no custom normals, we don't need to export
|
||||
* normals at all. This is also done by other software, see T71246. */
|
||||
if (!has_flat_shaded_poly && !CustomData_has_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void get_loop_normals(struct Mesh *mesh, std::vector<Imath::V3f> &normals)
|
||||
{
|
||||
MPoly *mp = mesh->mpoly;
|
||||
|
||||
MLoop *mloop = mesh->mloop;
|
||||
MLoop *ml = mloop;
|
||||
|
||||
MVert *verts = mesh->mvert;
|
||||
|
||||
BKE_mesh_calc_normals_split(mesh);
|
||||
const float(*lnors)[3] = static_cast<float(*)[3]>(CustomData_get_layer(&mesh->ldata, CD_NORMAL));
|
||||
BLI_assert(lnors != NULL || !"BKE_mesh_calc_normals_split() should have computed CD_NORMAL");
|
||||
|
||||
normals.clear();
|
||||
normals.resize(mesh->totloop);
|
||||
|
||||
/* NOTE: data needs to be written in the reverse order. */
|
||||
int abc_index = 0;
|
||||
|
||||
if (lnors) {
|
||||
for (int i = 0, e = mesh->totpoly; i < e; i++, mp++) {
|
||||
for (int j = mp->totloop - 1; j >= 0; j--, abc_index++) {
|
||||
int blender_index = mp->loopstart + j;
|
||||
copy_yup_from_zup(normals[abc_index].getValue(), lnors[blender_index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
float no[3];
|
||||
|
||||
for (int i = 0, e = mesh->totpoly; i < e; i++, mp++) {
|
||||
ml = mloop + mp->loopstart + (mp->totloop - 1);
|
||||
|
||||
/* Flat shaded, use common normal for all verts. */
|
||||
if ((mp->flag & ME_SMOOTH) == 0) {
|
||||
BKE_mesh_calc_poly_normal(mp, ml - (mp->totloop - 1), verts, no);
|
||||
|
||||
for (int j = 0; j < mp->totloop; ml--, j++, abc_index++) {
|
||||
copy_yup_from_zup(normals[abc_index].getValue(), no);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Smooth shaded, use individual vert normals. */
|
||||
for (int j = 0; j < mp->totloop; ml--, j++, abc_index++) {
|
||||
normal_short_to_float_v3(no, verts[ml->v].no);
|
||||
copy_yup_from_zup(normals[abc_index].getValue(), no);
|
||||
}
|
||||
}
|
||||
MPoly *mp = mesh->mpoly;
|
||||
for (int i = 0, e = mesh->totpoly; i < e; i++, mp++) {
|
||||
for (int j = mp->totloop - 1; j >= 0; j--, abc_index++) {
|
||||
int blender_index = mp->loopstart + j;
|
||||
copy_yup_from_zup(normals[abc_index].getValue(), lnors[blender_index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -409,11 +376,10 @@ void AbcGenericMeshWriter::writeMesh(struct Mesh *mesh)
|
||||
std::vector<Imath::V3f> points, normals;
|
||||
std::vector<int32_t> poly_verts, loop_counts;
|
||||
std::vector<Imath::V3f> velocities;
|
||||
|
||||
bool export_loop_normals = (mesh->flag & ME_AUTOSMOOTH) != 0;
|
||||
bool has_flat_shaded_poly = false;
|
||||
|
||||
get_vertices(mesh, points);
|
||||
get_topology(mesh, poly_verts, loop_counts, export_loop_normals);
|
||||
get_topology(mesh, poly_verts, loop_counts, has_flat_shaded_poly);
|
||||
|
||||
if (m_first_frame && m_settings.export_face_sets) {
|
||||
writeFaceSets(mesh, m_mesh_schema);
|
||||
@@ -441,16 +407,11 @@ void AbcGenericMeshWriter::writeMesh(struct Mesh *mesh)
|
||||
}
|
||||
|
||||
if (m_settings.export_normals) {
|
||||
if (export_loop_normals) {
|
||||
get_loop_normals(mesh, normals);
|
||||
}
|
||||
else {
|
||||
get_vertex_normals(mesh, normals);
|
||||
}
|
||||
get_loop_normals(mesh, normals, has_flat_shaded_poly);
|
||||
|
||||
ON3fGeomParam::Sample normals_sample;
|
||||
if (!normals.empty()) {
|
||||
normals_sample.setScope(export_loop_normals ? kFacevaryingScope : kVertexScope);
|
||||
normals_sample.setScope(kFacevaryingScope);
|
||||
normals_sample.setVals(V3fArraySample(normals));
|
||||
}
|
||||
|
||||
@@ -475,11 +436,10 @@ void AbcGenericMeshWriter::writeSubD(struct Mesh *mesh)
|
||||
std::vector<Imath::V3f> points;
|
||||
std::vector<int32_t> poly_verts, loop_counts;
|
||||
std::vector<int32_t> crease_indices, crease_lengths;
|
||||
|
||||
bool export_loop_normals = false;
|
||||
bool has_flat_poly = false;
|
||||
|
||||
get_vertices(mesh, points);
|
||||
get_topology(mesh, poly_verts, loop_counts, export_loop_normals);
|
||||
get_topology(mesh, poly_verts, loop_counts, has_flat_poly);
|
||||
get_creases(mesh, crease_indices, crease_lengths, crease_sharpness);
|
||||
|
||||
if (m_first_frame && m_settings.export_face_sets) {
|
||||
@@ -756,10 +716,6 @@ struct AbcMeshData {
|
||||
P3fArraySamplePtr positions;
|
||||
P3fArraySamplePtr ceil_positions;
|
||||
|
||||
N3fArraySamplePtr vertex_normals;
|
||||
N3fArraySamplePtr loop_normals;
|
||||
bool poly_flag_smooth;
|
||||
|
||||
V2fArraySamplePtr uvs;
|
||||
UInt32ArraySamplePtr uvs_indices;
|
||||
};
|
||||
@@ -786,7 +742,6 @@ static void read_mverts(CDStreamConfig &config, const AbcMeshData &mesh_data)
|
||||
{
|
||||
MVert *mverts = config.mvert;
|
||||
const P3fArraySamplePtr &positions = mesh_data.positions;
|
||||
const N3fArraySamplePtr &normals = mesh_data.vertex_normals;
|
||||
|
||||
if (config.weight != 0.0f && mesh_data.ceil_positions != NULL &&
|
||||
mesh_data.ceil_positions->size() == positions->size()) {
|
||||
@@ -794,12 +749,10 @@ static void read_mverts(CDStreamConfig &config, const AbcMeshData &mesh_data)
|
||||
return;
|
||||
}
|
||||
|
||||
read_mverts(mverts, positions, normals);
|
||||
read_mverts(mverts, positions, nullptr);
|
||||
}
|
||||
|
||||
void read_mverts(MVert *mverts,
|
||||
const P3fArraySamplePtr &positions,
|
||||
const N3fArraySamplePtr &normals)
|
||||
void read_mverts(MVert *mverts, const P3fArraySamplePtr positions, const N3fArraySamplePtr normals)
|
||||
{
|
||||
for (int i = 0; i < positions->size(); i++) {
|
||||
MVert &mvert = mverts[i];
|
||||
@@ -846,12 +799,9 @@ static void read_mpolys(CDStreamConfig &config, const AbcMeshData &mesh_data)
|
||||
poly.loopstart = loop_index;
|
||||
poly.totloop = face_size;
|
||||
|
||||
if (mesh_data.poly_flag_smooth) {
|
||||
poly.flag |= ME_SMOOTH;
|
||||
}
|
||||
else {
|
||||
poly.flag &= ~ME_SMOOTH;
|
||||
}
|
||||
/* Polygons are always assumed to be smooth-shaded. If the Alembic mesh should be flat-shaded,
|
||||
* this is encoded in custom loop normals. See T71246. */
|
||||
poly.flag |= ME_SMOOTH;
|
||||
|
||||
/* NOTE: Alembic data is stored in the reverse order. */
|
||||
rev_loop_index = loop_index + (face_size - 1);
|
||||
@@ -879,26 +829,27 @@ static void read_mpolys(CDStreamConfig &config, const AbcMeshData &mesh_data)
|
||||
BKE_mesh_calc_edges(config.mesh, false, false);
|
||||
}
|
||||
|
||||
static void process_normals(CDStreamConfig &config, const AbcMeshData &mesh_data)
|
||||
static void process_no_normals(CDStreamConfig &config)
|
||||
{
|
||||
Mesh *mesh = config.mesh;
|
||||
/* Absense of normals in the Alembic mesh is interpreted as 'smooth'. */
|
||||
BKE_mesh_calc_normals(config.mesh);
|
||||
}
|
||||
|
||||
if (!mesh_data.loop_normals) {
|
||||
BKE_mesh_calc_normals(config.mesh);
|
||||
/* Don't touch the ME_AUTOSMOOTH flag in this case. It can be used by artists to toggle between
|
||||
* flat/smooth shaded when the Alembic mesh doesn't contain loop normals. */
|
||||
static void process_loop_normals(CDStreamConfig &config, const N3fArraySamplePtr loop_normals_ptr)
|
||||
{
|
||||
size_t loop_count = loop_normals_ptr->size();
|
||||
|
||||
if (loop_count == 0) {
|
||||
process_no_normals(config);
|
||||
return;
|
||||
}
|
||||
|
||||
config.mesh->flag |= ME_AUTOSMOOTH;
|
||||
|
||||
const Alembic::AbcGeom::N3fArraySample &loop_normals = *mesh_data.loop_normals;
|
||||
long int loop_count = loop_normals.size();
|
||||
|
||||
float(*lnors)[3] = static_cast<float(*)[3]>(
|
||||
MEM_malloc_arrayN(loop_count, sizeof(float[3]), "ABC::FaceNormals"));
|
||||
|
||||
Mesh *mesh = config.mesh;
|
||||
MPoly *mpoly = mesh->mpoly;
|
||||
const N3fArraySample &loop_normals = *loop_normals_ptr;
|
||||
int abc_index = 0;
|
||||
for (int i = 0, e = mesh->totpoly; i < e; i++, mpoly++) {
|
||||
/* As usual, ABC orders the loops in reverse. */
|
||||
@@ -907,11 +858,63 @@ static void process_normals(CDStreamConfig &config, const AbcMeshData &mesh_data
|
||||
copy_zup_from_yup(lnors[blender_index], loop_normals[abc_index].getValue());
|
||||
}
|
||||
}
|
||||
BKE_mesh_set_custom_normals(config.mesh, lnors);
|
||||
|
||||
mesh->flag |= ME_AUTOSMOOTH;
|
||||
BKE_mesh_set_custom_normals(mesh, lnors);
|
||||
|
||||
MEM_freeN(lnors);
|
||||
}
|
||||
|
||||
static void process_vertex_normals(CDStreamConfig &config,
|
||||
const N3fArraySamplePtr vertex_normals_ptr)
|
||||
{
|
||||
size_t normals_count = vertex_normals_ptr->size();
|
||||
if (normals_count == 0) {
|
||||
process_no_normals(config);
|
||||
return;
|
||||
}
|
||||
|
||||
float(*vnors)[3] = static_cast<float(*)[3]>(
|
||||
MEM_malloc_arrayN(normals_count, sizeof(float[3]), "ABC::VertexNormals"));
|
||||
|
||||
const N3fArraySample &vertex_normals = *vertex_normals_ptr;
|
||||
for (int index = 0; index < normals_count; index++) {
|
||||
copy_zup_from_yup(vnors[index], vertex_normals[index].getValue());
|
||||
}
|
||||
|
||||
config.mesh->flag |= ME_AUTOSMOOTH;
|
||||
BKE_mesh_set_custom_normals_from_vertices(config.mesh, vnors);
|
||||
MEM_freeN(vnors);
|
||||
}
|
||||
|
||||
static void process_normals(CDStreamConfig &config,
|
||||
const IN3fGeomParam &normals,
|
||||
const ISampleSelector &selector)
|
||||
{
|
||||
if (!normals.valid()) {
|
||||
process_no_normals(config);
|
||||
return;
|
||||
}
|
||||
|
||||
IN3fGeomParam::Sample normsamp = normals.getExpandedValue(selector);
|
||||
Alembic::AbcGeom::GeometryScope scope = normals.getScope();
|
||||
|
||||
switch (scope) {
|
||||
case Alembic::AbcGeom::kFacevaryingScope: // 'Vertex Normals' in Houdini.
|
||||
process_loop_normals(config, normsamp.getVals());
|
||||
break;
|
||||
case Alembic::AbcGeom::kVertexScope:
|
||||
case Alembic::AbcGeom::kVaryingScope: // 'Point Normals' in Houdini.
|
||||
process_vertex_normals(config, normsamp.getVals());
|
||||
break;
|
||||
case Alembic::AbcGeom::kConstantScope:
|
||||
case Alembic::AbcGeom::kUniformScope:
|
||||
case Alembic::AbcGeom::kUnknownScope:
|
||||
process_no_normals(config);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ABC_INLINE void read_uvs_params(CDStreamConfig &config,
|
||||
AbcMeshData &abc_data,
|
||||
const IV2fGeomParam &uv,
|
||||
@@ -942,34 +945,6 @@ ABC_INLINE void read_uvs_params(CDStreamConfig &config,
|
||||
}
|
||||
}
|
||||
|
||||
ABC_INLINE void read_normals_params(AbcMeshData &abc_data,
|
||||
const IN3fGeomParam &normals,
|
||||
const ISampleSelector &selector)
|
||||
{
|
||||
if (!normals.valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
IN3fGeomParam::Sample normsamp = normals.getExpandedValue(selector);
|
||||
|
||||
Alembic::AbcGeom::GeometryScope scope = normals.getScope();
|
||||
switch (scope) {
|
||||
case Alembic::AbcGeom::kFacevaryingScope:
|
||||
abc_data.loop_normals = normsamp.getVals();
|
||||
break;
|
||||
case Alembic::AbcGeom::kVertexScope:
|
||||
case Alembic::AbcGeom::kVaryingScope:
|
||||
/* Vertex normals from ABC aren't handled for now. */
|
||||
abc_data.poly_flag_smooth = true;
|
||||
abc_data.vertex_normals = N3fArraySamplePtr();
|
||||
break;
|
||||
case Alembic::AbcGeom::kConstantScope:
|
||||
case Alembic::AbcGeom::kUniformScope:
|
||||
case Alembic::AbcGeom::kUnknownScope:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void *add_customdata_cb(Mesh *mesh, const char *name, int data_type)
|
||||
{
|
||||
CustomDataType cd_data_type = static_cast<CustomDataType>(data_type);
|
||||
@@ -1020,12 +995,6 @@ static void read_mesh_sample(const std::string &iobject_full_name,
|
||||
abc_mesh_data.face_indices = sample.getFaceIndices();
|
||||
abc_mesh_data.positions = sample.getPositions();
|
||||
|
||||
/* The auto-smoothing flag can be used by artists when the Alembic file does not contain custom
|
||||
* loop normals. Auto-smoothing only works when polys are marked as smooth. */
|
||||
abc_mesh_data.poly_flag_smooth = (config.mesh->flag & ME_AUTOSMOOTH);
|
||||
|
||||
read_normals_params(abc_mesh_data, schema.getNormalsParam(), selector);
|
||||
|
||||
get_weight_and_index(config, schema.getTimeSampling(), schema.getNumSamples());
|
||||
|
||||
if (config.weight != 0.0f) {
|
||||
@@ -1044,7 +1013,7 @@ static void read_mesh_sample(const std::string &iobject_full_name,
|
||||
|
||||
if ((settings->read_flag & MOD_MESHSEQ_READ_POLY) != 0) {
|
||||
read_mpolys(config, abc_mesh_data);
|
||||
process_normals(config, abc_mesh_data);
|
||||
process_normals(config, schema.getNormalsParam(), selector);
|
||||
}
|
||||
|
||||
if ((settings->read_flag & (MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)) != 0) {
|
||||
@@ -1316,8 +1285,6 @@ static void read_subd_sample(const std::string &iobject_full_name,
|
||||
AbcMeshData abc_mesh_data;
|
||||
abc_mesh_data.face_counts = sample.getFaceCounts();
|
||||
abc_mesh_data.face_indices = sample.getFaceIndices();
|
||||
abc_mesh_data.vertex_normals = N3fArraySamplePtr();
|
||||
abc_mesh_data.loop_normals = N3fArraySamplePtr();
|
||||
abc_mesh_data.positions = sample.getPositions();
|
||||
|
||||
get_weight_and_index(config, schema.getTimeSampling(), schema.getNumSamples());
|
||||
@@ -1339,12 +1306,9 @@ static void read_subd_sample(const std::string &iobject_full_name,
|
||||
if ((settings->read_flag & MOD_MESHSEQ_READ_POLY) != 0) {
|
||||
/* Alembic's 'SubD' scheme is used to store subdivision surfaces, i.e. the pre-subdivision
|
||||
* mesh. Currently we don't add a subdivision modifier when we load such data. This code is
|
||||
* assuming that the subdivided surface should be smooth, and sets a flag that will eventually
|
||||
* mark all polygons as such. */
|
||||
abc_mesh_data.poly_flag_smooth = true;
|
||||
|
||||
* assuming that the subdivided surface should be smooth. */
|
||||
read_mpolys(config, abc_mesh_data);
|
||||
process_normals(config, abc_mesh_data);
|
||||
process_no_normals(config);
|
||||
}
|
||||
|
||||
if ((settings->read_flag & (MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)) != 0) {
|
||||
|
@@ -148,8 +148,8 @@ class AbcSubDReader : public AbcObjectReader {
|
||||
/* ************************************************************************** */
|
||||
|
||||
void read_mverts(MVert *mverts,
|
||||
const Alembic::AbcGeom::P3fArraySamplePtr &positions,
|
||||
const Alembic::AbcGeom::N3fArraySamplePtr &normals);
|
||||
const Alembic::AbcGeom::P3fArraySamplePtr positions,
|
||||
const Alembic::AbcGeom::N3fArraySamplePtr normals);
|
||||
|
||||
CDStreamConfig get_config(struct Mesh *mesh);
|
||||
|
||||
|
@@ -191,12 +191,8 @@ struct bConstraintOb *BKE_constraints_make_evalob(struct Depsgraph *depsgraph,
|
||||
short datatype);
|
||||
void BKE_constraints_clear_evalob(struct bConstraintOb *cob);
|
||||
|
||||
void BKE_constraint_mat_convertspace(struct Object *ob,
|
||||
struct bPoseChannel *pchan,
|
||||
float mat[4][4],
|
||||
short from,
|
||||
short to,
|
||||
const bool keep_scale);
|
||||
void BKE_constraint_mat_convertspace(
|
||||
struct Object *ob, struct bPoseChannel *pchan, float mat[4][4], short from, short to);
|
||||
|
||||
void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph,
|
||||
struct Scene *scene,
|
||||
|
@@ -255,7 +255,7 @@ void BKE_constraints_clear_evalob(bConstraintOb *cob)
|
||||
* For now, this is only implemented for Objects and PoseChannels.
|
||||
*/
|
||||
void BKE_constraint_mat_convertspace(
|
||||
Object *ob, bPoseChannel *pchan, float mat[4][4], short from, short to, const bool keep_scale)
|
||||
Object *ob, bPoseChannel *pchan, float mat[4][4], short from, short to)
|
||||
{
|
||||
float diff_mat[4][4];
|
||||
float imat[4][4];
|
||||
@@ -282,7 +282,7 @@ void BKE_constraint_mat_convertspace(
|
||||
/* use pose-space as stepping stone for other spaces... */
|
||||
if (ELEM(to, CONSTRAINT_SPACE_LOCAL, CONSTRAINT_SPACE_PARLOCAL)) {
|
||||
/* call self with slightly different values */
|
||||
BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to, keep_scale);
|
||||
BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -318,7 +318,7 @@ void BKE_constraint_mat_convertspace(
|
||||
/* use pose-space as stepping stone for other spaces */
|
||||
if (ELEM(to, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_PARLOCAL)) {
|
||||
/* call self with slightly different values */
|
||||
BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to, keep_scale);
|
||||
BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -332,7 +332,7 @@ void BKE_constraint_mat_convertspace(
|
||||
/* use pose-space as stepping stone for other spaces */
|
||||
if (ELEM(to, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL)) {
|
||||
/* call self with slightly different values */
|
||||
BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to, keep_scale);
|
||||
BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -348,27 +348,6 @@ void BKE_constraint_mat_convertspace(
|
||||
invert_m4_m4_safe(imat, diff_mat);
|
||||
mul_m4_m4m4(mat, imat, mat);
|
||||
}
|
||||
else {
|
||||
/* Local space in this case will have to be defined as local to the owner's
|
||||
* transform-property-rotated axes. So subtract this rotation component.
|
||||
*/
|
||||
/* XXX This is actually an ugly hack, local space of a parent-less object *is* the same as
|
||||
* global space!
|
||||
* Think what we want actually here is some kind of 'Final Space', i.e
|
||||
* . once transformations are applied - users are often confused about this too,
|
||||
* this is not consistent with bones
|
||||
* local space either... Meh :|
|
||||
* --mont29
|
||||
*/
|
||||
BKE_object_to_mat4(ob, diff_mat);
|
||||
if (!keep_scale) {
|
||||
normalize_m4(diff_mat);
|
||||
}
|
||||
zero_v3(diff_mat[3]);
|
||||
|
||||
invert_m4_m4_safe(imat, diff_mat);
|
||||
mul_m4_m4m4(mat, imat, mat);
|
||||
}
|
||||
}
|
||||
else if (from == CONSTRAINT_SPACE_LOCAL && to == CONSTRAINT_SPACE_WORLD) {
|
||||
/* check that object has a parent - otherwise this won't work */
|
||||
@@ -377,19 +356,6 @@ void BKE_constraint_mat_convertspace(
|
||||
mul_m4_m4m4(diff_mat, ob->parent->obmat, ob->parentinv);
|
||||
mul_m4_m4m4(mat, diff_mat, mat);
|
||||
}
|
||||
else {
|
||||
/* Local space in this case will have to be defined as local to the owner's
|
||||
* transform-property-rotated axes. So add back this rotation component.
|
||||
*/
|
||||
/* XXX See comment above for world->local case... */
|
||||
BKE_object_to_mat4(ob, diff_mat);
|
||||
if (!keep_scale) {
|
||||
normalize_m4(diff_mat);
|
||||
}
|
||||
zero_v3(diff_mat[3]);
|
||||
|
||||
mul_m4_m4m4(mat, diff_mat, mat);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -575,7 +541,7 @@ static void constraint_target_to_mat4(Object *ob,
|
||||
/* Case OBJECT */
|
||||
if (substring[0] == '\0') {
|
||||
copy_m4_m4(mat, ob->obmat);
|
||||
BKE_constraint_mat_convertspace(ob, NULL, mat, from, to, false);
|
||||
BKE_constraint_mat_convertspace(ob, NULL, mat, from, to);
|
||||
}
|
||||
/* Case VERTEXGROUP */
|
||||
/* Current method just takes the average location of all the points in the
|
||||
@@ -588,11 +554,11 @@ static void constraint_target_to_mat4(Object *ob,
|
||||
*/
|
||||
else if (ob->type == OB_MESH) {
|
||||
contarget_get_mesh_mat(ob, substring, mat);
|
||||
BKE_constraint_mat_convertspace(ob, NULL, mat, from, to, false);
|
||||
BKE_constraint_mat_convertspace(ob, NULL, mat, from, to);
|
||||
}
|
||||
else if (ob->type == OB_LATTICE) {
|
||||
contarget_get_lattice_mat(ob, substring, mat);
|
||||
BKE_constraint_mat_convertspace(ob, NULL, mat, from, to, false);
|
||||
BKE_constraint_mat_convertspace(ob, NULL, mat, from, to);
|
||||
}
|
||||
/* Case BONE */
|
||||
else {
|
||||
@@ -656,7 +622,7 @@ static void constraint_target_to_mat4(Object *ob,
|
||||
}
|
||||
|
||||
/* convert matrix space as required */
|
||||
BKE_constraint_mat_convertspace(ob, pchan, mat, from, to, false);
|
||||
BKE_constraint_mat_convertspace(ob, pchan, mat, from, to);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4095,12 +4061,9 @@ static void shrinkwrap_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
|
||||
}
|
||||
|
||||
/* Transform normal into requested space */
|
||||
/* Note that in this specific case, we need to keep scaling in non-parented 'local2world'
|
||||
* object case, because SpaceTransform also takes it into account when handling normals.
|
||||
* See T42447. */
|
||||
unit_m4(mat);
|
||||
BKE_constraint_mat_convertspace(
|
||||
cob->ob, cob->pchan, mat, CONSTRAINT_SPACE_LOCAL, scon->projAxisSpace, true);
|
||||
cob->ob, cob->pchan, mat, CONSTRAINT_SPACE_LOCAL, scon->projAxisSpace);
|
||||
invert_m4(mat);
|
||||
mul_mat3_m4_v3(mat, no);
|
||||
|
||||
@@ -5834,7 +5797,7 @@ void BKE_constraints_solve(struct Depsgraph *depsgraph,
|
||||
|
||||
/* move owner matrix into right space */
|
||||
BKE_constraint_mat_convertspace(
|
||||
cob->ob, cob->pchan, cob->matrix, CONSTRAINT_SPACE_WORLD, con->ownspace, false);
|
||||
cob->ob, cob->pchan, cob->matrix, CONSTRAINT_SPACE_WORLD, con->ownspace);
|
||||
|
||||
/* prepare targets for constraint solving */
|
||||
BKE_constraint_targets_for_solving_get(depsgraph, con, cob, &targets, ctime);
|
||||
@@ -5853,7 +5816,7 @@ void BKE_constraints_solve(struct Depsgraph *depsgraph,
|
||||
/* move owner back into worldspace for next constraint/other business */
|
||||
if ((con->flag & CONSTRAINT_SPACEONCE) == 0) {
|
||||
BKE_constraint_mat_convertspace(
|
||||
cob->ob, cob->pchan, cob->matrix, con->ownspace, CONSTRAINT_SPACE_WORLD, false);
|
||||
cob->ob, cob->pchan, cob->matrix, con->ownspace, CONSTRAINT_SPACE_WORLD);
|
||||
}
|
||||
|
||||
/* Interpolate the enforcement, to blend result of constraint into final owner transform
|
||||
|
@@ -1560,7 +1560,7 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar)
|
||||
/* extract transform just like how the constraints do it! */
|
||||
copy_m4_m4(mat, pchan->pose_mat);
|
||||
BKE_constraint_mat_convertspace(
|
||||
ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false);
|
||||
ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL);
|
||||
|
||||
/* ... and from that, we get our transform */
|
||||
copy_v3_v3(tmp_loc, mat[3]);
|
||||
@@ -1586,7 +1586,7 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar)
|
||||
/* extract transform just like how the constraints do it! */
|
||||
copy_m4_m4(mat, ob->obmat);
|
||||
BKE_constraint_mat_convertspace(
|
||||
ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false);
|
||||
ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL);
|
||||
|
||||
/* ... and from that, we get our transform */
|
||||
copy_v3_v3(tmp_loc, mat[3]);
|
||||
@@ -1663,7 +1663,7 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
|
||||
/* just like how the constraints do it! */
|
||||
copy_m4_m4(mat, pchan->pose_mat);
|
||||
BKE_constraint_mat_convertspace(
|
||||
ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false);
|
||||
ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL);
|
||||
}
|
||||
else {
|
||||
/* specially calculate local matrix, since chan_mat is not valid
|
||||
@@ -1691,7 +1691,7 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
|
||||
/* just like how the constraints do it! */
|
||||
copy_m4_m4(mat, ob->obmat);
|
||||
BKE_constraint_mat_convertspace(
|
||||
ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false);
|
||||
ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL);
|
||||
}
|
||||
else {
|
||||
/* transforms to matrix */
|
||||
|
@@ -146,7 +146,8 @@ bool python_driver_exression_depends_on_time(const char *expression)
|
||||
|
||||
bool driver_target_depends_on_time(const DriverTarget *target)
|
||||
{
|
||||
if (target->idtype == ID_SCE && STREQ(target->rna_path, "frame_current")) {
|
||||
if (target->idtype == ID_SCE &&
|
||||
(target->rna_path != NULL && STREQ(target->rna_path, "frame_current"))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@@ -323,7 +323,7 @@ static void rna_Object_mat_convert_space(Object *ob,
|
||||
}
|
||||
}
|
||||
|
||||
BKE_constraint_mat_convertspace(ob, pchan, (float(*)[4])mat_ret, from, to, false);
|
||||
BKE_constraint_mat_convertspace(ob, pchan, (float(*)[4])mat_ret, from, to);
|
||||
}
|
||||
|
||||
static void rna_Object_calc_matrix_camera(Object *ob,
|
||||
|
@@ -82,7 +82,10 @@ void *node_initexec_curves(bNodeExecContext *UNUSED(context),
|
||||
void node_blend_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
|
||||
{
|
||||
const char *name;
|
||||
RNA_enum_name(rna_enum_ramp_blend_items, node->custom1, &name);
|
||||
bool enum_label = RNA_enum_name(rna_enum_ramp_blend_items, node->custom1, &name);
|
||||
if (!enum_label) {
|
||||
name = "Unknown";
|
||||
}
|
||||
BLI_strncpy(label, IFACE_(name), maxlen);
|
||||
}
|
||||
|
||||
@@ -96,21 +99,30 @@ void node_image_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int ma
|
||||
void node_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
|
||||
{
|
||||
const char *name;
|
||||
RNA_enum_name(rna_enum_node_math_items, node->custom1, &name);
|
||||
bool enum_label = RNA_enum_name(rna_enum_node_math_items, node->custom1, &name);
|
||||
if (!enum_label) {
|
||||
name = "Unknown";
|
||||
}
|
||||
BLI_strncpy(label, IFACE_(name), maxlen);
|
||||
}
|
||||
|
||||
void node_vector_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
|
||||
{
|
||||
const char *name;
|
||||
RNA_enum_name(rna_enum_node_vec_math_items, node->custom1, &name);
|
||||
bool enum_label = RNA_enum_name(rna_enum_node_vec_math_items, node->custom1, &name);
|
||||
if (!enum_label) {
|
||||
name = "Unknown";
|
||||
}
|
||||
BLI_strncpy(label, IFACE_(name), maxlen);
|
||||
}
|
||||
|
||||
void node_filter_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
|
||||
{
|
||||
const char *name;
|
||||
RNA_enum_name(rna_enum_node_filter_items, node->custom1, &name);
|
||||
bool enum_label = RNA_enum_name(rna_enum_node_filter_items, node->custom1, &name);
|
||||
if (!enum_label) {
|
||||
name = "Unknown";
|
||||
}
|
||||
BLI_strncpy(label, IFACE_(name), maxlen);
|
||||
}
|
||||
|
||||
|
@@ -50,7 +50,12 @@ static int gpu_shader_mapping(GPUMaterial *mat,
|
||||
[NODE_MAPPING_TYPE_NORMAL] = "mapping_normal",
|
||||
};
|
||||
|
||||
return GPU_stack_link(mat, node, names[node->custom1], in, out);
|
||||
if (node->custom1 < ARRAY_SIZE(names) && names[node->custom1]) {
|
||||
return GPU_stack_link(mat, node, names[node->custom1], in, out);
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void node_shader_update_mapping(bNodeTree *UNUSED(ntree), bNode *node)
|
||||
|
@@ -68,14 +68,19 @@ static int gpu_shader_math(GPUMaterial *mat,
|
||||
[NODE_MATH_ARCTAN2] = "math_arctan2",
|
||||
};
|
||||
|
||||
GPU_stack_link(mat, node, names[node->custom1], in, out);
|
||||
if (node->custom1 < ARRAY_SIZE(names) && names[node->custom1]) {
|
||||
int ret = GPU_stack_link(mat, node, names[node->custom1], in, out);
|
||||
|
||||
if (node->custom2 & SHD_MATH_CLAMP) {
|
||||
float min[3] = {0.0f, 0.0f, 0.0f};
|
||||
float max[3] = {1.0f, 1.0f, 1.0f};
|
||||
GPU_link(mat, "clamp_value", out[0].link, GPU_constant(min), GPU_constant(max), &out[0].link);
|
||||
if (ret && node->custom2 & SHD_MATH_CLAMP) {
|
||||
float min[3] = {0.0f, 0.0f, 0.0f};
|
||||
float max[3] = {1.0f, 1.0f, 1.0f};
|
||||
GPU_link(mat, "clamp_value", out[0].link, GPU_constant(min), GPU_constant(max), &out[0].link);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void node_shader_update_math(bNodeTree *UNUSED(ntree), bNode *node)
|
||||
|
@@ -88,13 +88,18 @@ static int gpu_shader_mix_rgb(GPUMaterial *mat,
|
||||
"mix_linear",
|
||||
};
|
||||
|
||||
int ret = GPU_stack_link(mat, node, names[node->custom1], in, out);
|
||||
if (ret && node->custom2 & SHD_MIXRGB_CLAMP) {
|
||||
float min[3] = {0.0f, 0.0f, 0.0f};
|
||||
float max[3] = {1.0f, 1.0f, 1.0f};
|
||||
GPU_link(mat, "clamp_color", out[0].link, GPU_constant(min), GPU_constant(max), &out[0].link);
|
||||
if (node->custom1 < ARRAY_SIZE(names) && names[node->custom1]) {
|
||||
int ret = GPU_stack_link(mat, node, names[node->custom1], in, out);
|
||||
if (ret && node->custom2 & SHD_MIXRGB_CLAMP) {
|
||||
float min[3] = {0.0f, 0.0f, 0.0f};
|
||||
float max[3] = {1.0f, 1.0f, 1.0f};
|
||||
GPU_link(mat, "clamp_color", out[0].link, GPU_constant(min), GPU_constant(max), &out[0].link);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void register_node_type_sh_mix_rgb(void)
|
||||
|
@@ -50,7 +50,12 @@ static int gpu_shader_tex_white_noise(GPUMaterial *mat,
|
||||
"node_white_noise_4d",
|
||||
};
|
||||
|
||||
return GPU_stack_link(mat, node, names[node->custom1], in, out);
|
||||
if (node->custom1 < ARRAY_SIZE(names) && names[node->custom1]) {
|
||||
return GPU_stack_link(mat, node, names[node->custom1], in, out);
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void node_shader_update_tex_white_noise(bNodeTree *UNUSED(ntree), bNode *node)
|
||||
|
@@ -65,8 +65,12 @@ static int gpu_shader_vector_math(GPUMaterial *mat,
|
||||
[NODE_VECTOR_MATH_MAXIMUM] = "vector_math_maximum",
|
||||
};
|
||||
|
||||
GPU_stack_link(mat, node, names[node->custom1], in, out);
|
||||
return true;
|
||||
if (node->custom1 < ARRAY_SIZE(names) && names[node->custom1]) {
|
||||
return GPU_stack_link(mat, node, names[node->custom1], in, out);
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void node_shader_update_vector_math(bNodeTree *UNUSED(ntree), bNode *node)
|
||||
|
@@ -810,7 +810,8 @@ static PyObject *M_Geometry_intersect_point_line(PyObject *UNUSED(self), PyObjec
|
||||
PyDoc_STRVAR(M_Geometry_intersect_point_tri_doc,
|
||||
".. function:: intersect_point_tri(pt, tri_p1, tri_p2, tri_p3)\n"
|
||||
"\n"
|
||||
" Takes 4 vectors: one is the point and the next 3 define the triangle.\n"
|
||||
" Takes 4 vectors: one is the point and the next 3 define the triangle. Projects "
|
||||
"the point onto the triangle plane and checks if it is within the triangle.\n"
|
||||
"\n"
|
||||
" :arg pt: Point\n"
|
||||
" :type pt: :class:`mathutils.Vector`\n"
|
||||
@@ -853,6 +854,49 @@ static PyObject *M_Geometry_intersect_point_tri(PyObject *UNUSED(self), PyObject
|
||||
}
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(M_Geometry_closest_point_on_tri_doc,
|
||||
".. function:: closest_point_on_tri(pt, tri_p1, tri_p2, tri_p3)\n"
|
||||
"\n"
|
||||
" Takes 4 vectors: one is the point and the next 3 define the triangle.\n"
|
||||
"\n"
|
||||
" :arg pt: Point\n"
|
||||
" :type pt: :class:`mathutils.Vector`\n"
|
||||
" :arg tri_p1: First point of the triangle\n"
|
||||
" :type tri_p1: :class:`mathutils.Vector`\n"
|
||||
" :arg tri_p2: Second point of the triangle\n"
|
||||
" :type tri_p2: :class:`mathutils.Vector`\n"
|
||||
" :arg tri_p3: Third point of the triangle\n"
|
||||
" :type tri_p3: :class:`mathutils.Vector`\n"
|
||||
" :return: The closest point of the triangle.\n"
|
||||
" :rtype: :class:`mathutils.Vector`\n");
|
||||
static PyObject *M_Geometry_closest_point_on_tri(PyObject *UNUSED(self), PyObject *args)
|
||||
{
|
||||
const char *error_prefix = "closest_point_on_tri";
|
||||
PyObject *py_pt, *py_tri[3];
|
||||
float pt[3], tri[3][3];
|
||||
float vi[3];
|
||||
int i;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "OOOO:closest_point_on_tri", &py_pt, UNPACK3_EX(&, py_tri, ))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mathutils_array_parse(pt, 2, 3 | MU_ARRAY_SPILL | MU_ARRAY_ZERO, py_pt, error_prefix) ==
|
||||
-1) {
|
||||
return NULL;
|
||||
}
|
||||
for (i = 0; i < ARRAY_SIZE(tri); i++) {
|
||||
if (mathutils_array_parse(
|
||||
tri[i], 2, 3 | MU_ARRAY_SPILL | MU_ARRAY_ZERO, py_tri[i], error_prefix) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
closest_on_tri_to_point_v3(vi, pt, UNPACK3(tri));
|
||||
|
||||
return Vector_CreatePyObject(vi, 3, NULL);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
M_Geometry_intersect_point_tri_2d_doc,
|
||||
".. function:: intersect_point_tri_2d(pt, tri_p1, tri_p2, tri_p3)\n"
|
||||
@@ -1683,6 +1727,10 @@ static PyMethodDef M_Geometry_methods[] = {
|
||||
(PyCFunction)M_Geometry_intersect_point_tri,
|
||||
METH_VARARGS,
|
||||
M_Geometry_intersect_point_tri_doc},
|
||||
{"closest_point_on_tri",
|
||||
(PyCFunction)M_Geometry_closest_point_on_tri,
|
||||
METH_VARARGS,
|
||||
M_Geometry_closest_point_on_tri_doc},
|
||||
{"intersect_point_tri_2d",
|
||||
(PyCFunction)M_Geometry_intersect_point_tri_2d,
|
||||
METH_VARARGS,
|
||||
|
Reference in New Issue
Block a user