Fix #117338: Texture paint sampling broken with modifiers #120259
|
@ -18,7 +18,9 @@
|
|||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math_color.h"
|
||||
#include "BLI_math_geom.h"
|
||||
#include "BLI_math_matrix.h"
|
||||
#include "BLI_math_matrix.hh"
|
||||
#include "BLI_math_vector.hh"
|
||||
#include "BLI_rect.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
@ -26,6 +28,7 @@
|
|||
#include "BLT_translation.hh"
|
||||
|
||||
#include "BKE_brush.hh"
|
||||
#include "BKE_bvhutils.hh"
|
||||
#include "BKE_colortools.hh"
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_customdata.hh"
|
||||
|
@ -33,6 +36,7 @@
|
|||
#include "BKE_layer.hh"
|
||||
#include "BKE_material.h"
|
||||
#include "BKE_mesh.hh"
|
||||
#include "BKE_mesh_sample.hh"
|
||||
#include "BKE_object.hh"
|
||||
#include "BKE_paint.hh"
|
||||
#include "BKE_report.hh"
|
||||
|
@ -44,9 +48,6 @@
|
|||
#include "RNA_define.hh"
|
||||
#include "RNA_prototypes.h"
|
||||
|
||||
#include "GPU_matrix.hh"
|
||||
#include "GPU_state.hh"
|
||||
|
||||
#include "IMB_imbuf_types.hh"
|
||||
#include "IMB_interp.hh"
|
||||
|
||||
|
@ -59,8 +60,6 @@
|
|||
#include "BLI_sys_types.h"
|
||||
#include "ED_mesh.hh" /* for face mask functions */
|
||||
|
||||
#include "DRW_select_buffer.hh"
|
||||
|
||||
#include "WM_api.hh"
|
||||
#include "WM_types.hh"
|
||||
|
||||
|
@ -202,168 +201,104 @@ void paint_stroke_operator_properties(wmOperatorType *ot)
|
|||
|
||||
/* 3D Paint */
|
||||
|
||||
static void imapaint_project(const float matrix[4][4], const float co[3], float pco[4])
|
||||
{
|
||||
copy_v3_v3(pco, co);
|
||||
pco[3] = 1.0f;
|
||||
|
||||
mul_m4_v4(matrix, pco);
|
||||
}
|
||||
|
||||
static void imapaint_tri_weights(float matrix[4][4],
|
||||
const int view[4],
|
||||
const float v1[3],
|
||||
const float v2[3],
|
||||
const float v3[3],
|
||||
const float co[2],
|
||||
float w[3])
|
||||
{
|
||||
float pv1[4], pv2[4], pv3[4], h[3], divw;
|
||||
float wmat[3][3], invwmat[3][3];
|
||||
|
||||
/* compute barycentric coordinates */
|
||||
|
||||
/* project the verts */
|
||||
imapaint_project(matrix, v1, pv1);
|
||||
imapaint_project(matrix, v2, pv2);
|
||||
imapaint_project(matrix, v3, pv3);
|
||||
|
||||
/* do inverse view mapping, see gluProject man page */
|
||||
h[0] = (co[0] - view[0]) * 2.0f / view[2] - 1.0f;
|
||||
h[1] = (co[1] - view[1]) * 2.0f / view[3] - 1.0f;
|
||||
h[2] = 1.0f;
|
||||
|
||||
/* Solve for `(w1,w2,w3)/perspdiv` in:
|
||||
* `h * perspdiv = Project * Model * (w1 * v1 + w2 * v2 + w3 * v3)`. */
|
||||
|
||||
wmat[0][0] = pv1[0];
|
||||
wmat[1][0] = pv2[0];
|
||||
wmat[2][0] = pv3[0];
|
||||
wmat[0][1] = pv1[1];
|
||||
wmat[1][1] = pv2[1];
|
||||
wmat[2][1] = pv3[1];
|
||||
wmat[0][2] = pv1[3];
|
||||
wmat[1][2] = pv2[3];
|
||||
wmat[2][2] = pv3[3];
|
||||
|
||||
invert_m3_m3(invwmat, wmat);
|
||||
mul_m3_v3(invwmat, h);
|
||||
|
||||
copy_v3_v3(w, h);
|
||||
|
||||
/* w is still divided by `perspdiv`, make it sum to one */
|
||||
divw = w[0] + w[1] + w[2];
|
||||
if (divw != 0.0f) {
|
||||
mul_v3_fl(w, 1.0f / divw);
|
||||
}
|
||||
}
|
||||
|
||||
/* compute uv coordinates of mouse in face */
|
||||
static void imapaint_pick_uv(const Mesh *mesh_eval,
|
||||
Scene *scene,
|
||||
Object *ob_eval,
|
||||
uint faceindex,
|
||||
const int xy[2],
|
||||
float uv[2])
|
||||
static blender::float2 imapaint_pick_uv(const Mesh *mesh_eval,
|
||||
Scene *scene,
|
||||
Object *ob_eval,
|
||||
const int tri_index,
|
||||
const blender::float3 &bary_coord)
|
||||
{
|
||||
float p[2], w[3], absw, minabsw;
|
||||
float matrix[4][4], proj[4][4];
|
||||
int view[4];
|
||||
const ePaintCanvasSource mode = ePaintCanvasSource(scene->toolsettings->imapaint.mode);
|
||||
|
||||
const blender::Span<blender::int3> tris = mesh_eval->corner_tris();
|
||||
const blender::Span<int> tri_faces = mesh_eval->corner_tri_faces();
|
||||
|
||||
const blender::Span<blender::float3> positions = mesh_eval->vert_positions();
|
||||
const blender::Span<int> corner_verts = mesh_eval->corner_verts();
|
||||
const int *index_mp_to_orig = static_cast<const int *>(
|
||||
CustomData_get_layer(&mesh_eval->face_data, CD_ORIGINDEX));
|
||||
|
||||
/* get the needed opengl matrices */
|
||||
GPU_viewport_size_get_i(view);
|
||||
GPU_matrix_model_view_get(matrix);
|
||||
GPU_matrix_projection_get(proj);
|
||||
view[0] = view[1] = 0;
|
||||
mul_m4_m4m4(matrix, matrix, ob_eval->object_to_world().ptr());
|
||||
mul_m4_m4m4(matrix, proj, matrix);
|
||||
|
||||
minabsw = 1e10;
|
||||
uv[0] = uv[1] = 0.0;
|
||||
|
||||
const int *material_indices = (const int *)CustomData_get_layer_named(
|
||||
&mesh_eval->face_data, CD_PROP_INT32, "material_index");
|
||||
|
||||
/* test all faces in the derivedmesh with the original index of the picked face */
|
||||
/* face means poly here, not triangle, indeed */
|
||||
HooglyBoogly marked this conversation as resolved
|
||||
for (const int i : tris.index_range()) {
|
||||
const int face_i = tri_faces[i];
|
||||
const int findex = index_mp_to_orig ? index_mp_to_orig[face_i] : face_i;
|
||||
const int face_i = tri_faces[tri_index];
|
||||
|
||||
if (findex == faceindex) {
|
||||
const float(*mloopuv)[2];
|
||||
const float *tri_uv[3];
|
||||
float tri_co[3][3];
|
||||
const float(*mloopuv)[2];
|
||||
|
||||
for (int j = 3; j--;) {
|
||||
copy_v3_v3(tri_co[j], positions[corner_verts[tris[i][j]]]);
|
||||
}
|
||||
if (mode == PAINT_CANVAS_SOURCE_MATERIAL) {
|
||||
const Material *ma;
|
||||
const TexPaintSlot *slot;
|
||||
|
||||
if (mode == PAINT_CANVAS_SOURCE_MATERIAL) {
|
||||
const Material *ma;
|
||||
const TexPaintSlot *slot;
|
||||
ma = BKE_object_material_get(ob_eval,
|
||||
material_indices == nullptr ? 1 : material_indices[face_i] + 1);
|
||||
slot = &ma->texpaintslot[ma->paint_active_slot];
|
||||
|
||||
ma = BKE_object_material_get(
|
||||
ob_eval, material_indices == nullptr ? 1 : material_indices[face_i] + 1);
|
||||
slot = &ma->texpaintslot[ma->paint_active_slot];
|
||||
|
||||
if (!(slot && slot->uvname &&
|
||||
(mloopuv = static_cast<const float(*)[2]>(CustomData_get_layer_named(
|
||||
&mesh_eval->corner_data, CD_PROP_FLOAT2, slot->uvname)))))
|
||||
{
|
||||
mloopuv = static_cast<const float(*)[2]>(
|
||||
CustomData_get_layer(&mesh_eval->corner_data, CD_PROP_FLOAT2));
|
||||
}
|
||||
}
|
||||
else {
|
||||
mloopuv = static_cast<const float(*)[2]>(
|
||||
CustomData_get_layer(&mesh_eval->corner_data, CD_PROP_FLOAT2));
|
||||
}
|
||||
|
||||
tri_uv[0] = mloopuv[tris[i][0]];
|
||||
tri_uv[1] = mloopuv[tris[i][1]];
|
||||
tri_uv[2] = mloopuv[tris[i][2]];
|
||||
|
||||
p[0] = xy[0];
|
||||
p[1] = xy[1];
|
||||
|
||||
imapaint_tri_weights(matrix, view, UNPACK3(tri_co), p, w);
|
||||
absw = fabsf(w[0]) + fabsf(w[1]) + fabsf(w[2]);
|
||||
if (absw < minabsw) {
|
||||
uv[0] = tri_uv[0][0] * w[0] + tri_uv[1][0] * w[1] + tri_uv[2][0] * w[2];
|
||||
uv[1] = tri_uv[0][1] * w[0] + tri_uv[1][1] * w[1] + tri_uv[2][1] * w[2];
|
||||
minabsw = absw;
|
||||
}
|
||||
if (!(slot && slot->uvname &&
|
||||
(mloopuv = static_cast<const float(*)[2]>(CustomData_get_layer_named(
|
||||
&mesh_eval->corner_data, CD_PROP_FLOAT2, slot->uvname)))))
|
||||
{
|
||||
mloopuv = static_cast<const float(*)[2]>(
|
||||
CustomData_get_layer(&mesh_eval->corner_data, CD_PROP_FLOAT2));
|
||||
}
|
||||
}
|
||||
else {
|
||||
mloopuv = static_cast<const float(*)[2]>(
|
||||
CustomData_get_layer(&mesh_eval->corner_data, CD_PROP_FLOAT2));
|
||||
}
|
||||
|
||||
return blender::bke::mesh_surface_sample::sample_corner_attribute_with_bary_coords(
|
||||
bary_coord,
|
||||
tris[tri_index],
|
||||
blender::Span(reinterpret_cast<const blender::float2 *>(mloopuv), mesh_eval->corners_num));
|
||||
}
|
||||
|
||||
/* returns 0 if not found, otherwise 1 */
|
||||
static int imapaint_pick_face(ViewContext *vc, const int mval[2], uint *r_index, uint faces_num)
|
||||
static int imapaint_pick_face(ViewContext *vc,
|
||||
const int mval[2],
|
||||
int *r_tri_index,
|
||||
int *r_face_index,
|
||||
blender::float3 *r_bary_coord,
|
||||
const Mesh &mesh)
|
||||
{
|
||||
if (faces_num == 0) {
|
||||
using namespace blender;
|
||||
if (mesh.faces_num == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* sample only on the exact position */
|
||||
ED_view3d_select_id_validate(vc);
|
||||
*r_index = DRW_select_buffer_sample_point(vc->depsgraph, vc->region, vc->v3d, mval);
|
||||
BVHTreeFromMesh mesh_bvh;
|
||||
BKE_bvhtree_from_mesh_get(&mesh_bvh, &mesh, BVHTREE_FROM_CORNER_TRIS, 2);
|
||||
BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&mesh_bvh); });
|
||||
|
||||
if ((*r_index) == 0 || (*r_index) > uint(faces_num)) {
|
||||
float3 start_world, end_world;
|
||||
ED_view3d_win_to_segment_clipped(
|
||||
vc->depsgraph, vc->region, vc->v3d, float2(mval[0], mval[1]), start_world, end_world, true);
|
||||
|
||||
const float4x4 &world_to_object = vc->obact->world_to_object();
|
||||
const float3 start_object = math::transform_point(world_to_object, start_world);
|
||||
const float3 end_object = math::transform_point(world_to_object, end_world);
|
||||
|
||||
BVHTreeRayHit ray_hit;
|
||||
ray_hit.dist = FLT_MAX;
|
||||
ray_hit.index = -1;
|
||||
BLI_bvhtree_ray_cast(mesh_bvh.tree,
|
||||
start_object,
|
||||
math::normalize(end_object - start_object),
|
||||
0.0f,
|
||||
&ray_hit,
|
||||
mesh_bvh.raycast_callback,
|
||||
&mesh_bvh);
|
||||
if (ray_hit.index == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
(*r_index)--;
|
||||
const Span<float3> positions = mesh.vert_positions();
|
||||
const Span<int> corner_verts = mesh.corner_verts();
|
||||
const Span<int3> corner_tris = mesh.corner_tris();
|
||||
const int3 &tri = corner_tris[ray_hit.index];
|
||||
interp_weights_tri_v3(*r_bary_coord,
|
||||
positions[corner_verts[tri[0]]],
|
||||
positions[corner_verts[tri[1]]],
|
||||
positions[corner_verts[tri[2]]],
|
||||
ray_hit.co);
|
||||
|
||||
*r_tri_index = ray_hit.index;
|
||||
*r_face_index = mesh.corner_tri_faces()[ray_hit.index];
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -404,23 +339,18 @@ void paint_sample_color(
|
|||
bool use_material = (imapaint->mode == IMAGEPAINT_MODE_MATERIAL);
|
||||
|
||||
if (ob) {
|
||||
CustomData_MeshMasks cddata_masks = CD_MASK_BAREMESH;
|
||||
cddata_masks.pmask |= CD_MASK_ORIGINDEX;
|
||||
Mesh *mesh = (Mesh *)ob->data;
|
||||
const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval);
|
||||
const int *material_indices = (const int *)CustomData_get_layer_named(
|
||||
&mesh_eval->face_data, CD_PROP_INT32, "material_index");
|
||||
|
||||
const int mval[2] = {x, y};
|
||||
uint faceindex;
|
||||
uint faces_num = mesh->faces_num;
|
||||
|
||||
if (CustomData_has_layer(&mesh_eval->corner_data, CD_PROP_FLOAT2)) {
|
||||
ViewContext vc = ED_view3d_viewcontext_init(C, depsgraph);
|
||||
|
||||
view3d_operator_needs_opengl(C);
|
||||
|
||||
if (imapaint_pick_face(&vc, mval, &faceindex, faces_num)) {
|
||||
const int mval[2] = {x, y};
|
||||
int tri_index;
|
||||
float3 bary_coord;
|
||||
int faceindex;
|
||||
if (imapaint_pick_face(&vc, mval, &tri_index, &faceindex, &bary_coord, *mesh_eval)) {
|
||||
Image *image = nullptr;
|
||||
int interp = SHD_INTERP_LINEAR;
|
||||
|
||||
|
@ -449,8 +379,7 @@ void paint_sample_color(
|
|||
BKE_imageuser_default(&iuser);
|
||||
iuser.framenr = image->lastframe;
|
||||
|
||||
float uv[2];
|
||||
imapaint_pick_uv(mesh_eval, scene, ob_eval, faceindex, mval, uv);
|
||||
float2 uv = imapaint_pick_uv(mesh_eval, scene, ob_eval, tri_index, bary_coord);
|
||||
|
||||
if (image->source == IMA_SRC_TILED) {
|
||||
float new_uv[2];
|
||||
|
|
Loading…
Reference in New Issue
The comment is out=of-date now, and could be removed?