1
1

Compare commits

...

11 Commits

Author SHA1 Message Date
Julian Eisel
788c75ed87 Merge branch 'master' into viewport_bvh_select 2016-09-08 12:16:41 +02:00
Julian Eisel
1ffd9714b9 Add/use BKE_object_boundbox_to_worldspace 2016-08-28 15:59:39 +02:00
Julian Eisel
f501e495fb Merge branch 'master' into viewport_bvh_select 2016-08-28 15:27:30 +02:00
Julian Eisel
286a4ad6f9 Avoid allocating bounding boxes 2016-08-28 04:21:48 +02:00
Julian Eisel
68a891f2e5 Support selecting empties using new BVH selection
Adding support for all empty draw types was a bit more involved, but things work now ;)
2016-08-28 03:40:11 +02:00
Julian Eisel
af248f4941 Support selecting speakers using new BVH selection 2016-08-27 23:59:00 +02:00
Julian Eisel
c69f623699 Support selecting lamps using new BVH selection 2016-08-27 23:34:36 +02:00
Julian Eisel
ba938f1012 Correct license header 2016-08-26 00:24:46 +02:00
Julian Eisel
1063405219 Merge branch 'master' into viewport_bvh_select 2016-08-25 17:46:07 +02:00
Julian Eisel
61c972c3ef Fix crash on undo and file read 2016-08-25 17:45:01 +02:00
Julian Eisel
695da4fd62 Initial BVH based object mode selection
As part of the viewport project, we wanted to switch from OpenGL based to BVH based selection (see https://wiki.blender.org/index.php/Dev:2.8/Viewport#Discussion_Items). This should increase performance and make selection drawing and hence driver independent. (OpenGL selection was always an issue with buggy drivers.)

This commit adds initial functions for building and visualizing an object BVH (AABB) using the multi-threaded BLI_bvhtree and uses it for object mode selecting. Only basic selection works now, not taking care for movie clip editor selection syncing or so. One idea was to keep the actual BVH part a bit separate from selection, so that it can be reused e.g. for culling out objects out of view frustum before drawing.
Quite some speedup is already visible, but it's not fair to compare to previous selection, since we're only doing bounding box intesection checks currently. Detailed geometry intersection checks are not done yet, neither are overlapping objects handled.

One issue I faced was that some object types (cameras, lamps, speakers) are basically infinite small points with no visible bounding box. I added some functions to get the visual bounding box for those, but only implemented it for cameras so far.

Main TODOs I can see (random order):
* Selection should behave just like current OpenGL based selection.
* Lasso, Circle & Box select.
* The BVH tree is currently recreated on every redraw, more reasonable updating needs to be checked on. It's unsure if it's better to commonly recreate the entire tree or if we can use some more advanced caching and updating. The BLI_bvhtree isn't really flexible when it comes to updating (e.g. you can't insert objects after initial creating), so maybe adding a different BVH type will be needed.
* Do more detailed geometry intersection checks. OpenSubdiv needs some special attention here, since its geometry only lives on the GPU (AFAIK). It should be possible to send geometry patches from GPU to CPU so we can create AABBs for BVH ray casting.
* Better handling for overlapping geometry.
* BVH based selection for other modes (edit mode, pose mode, etc). I'd like to make the edit mode BVH lookups efficient enough to allow performant pre-selection highlighting.
* Allow selecting lamps and speakers (not possible currently).
2016-08-25 17:21:44 +02:00
27 changed files with 602 additions and 79 deletions

View File

@@ -38,6 +38,7 @@ extern "C" {
#include "DNA_vec_types.h"
struct BoundBox;
struct Camera;
struct Main;
struct Object;
@@ -64,6 +65,8 @@ void BKE_camera_object_mode(struct RenderData *rd, struct Object *ob);
int BKE_camera_sensor_fit(int sensor_fit, float sizex, float sizey);
float BKE_camera_sensor_size(int sensor_fit, float sensor_x, float sensor_y);
void BKE_camera_drawboundbox_get(const struct Scene *scene, const struct Object *ob, struct BoundBox *r_bb);
/* Camera Parameters:
*
* Intermediate struct for storing camera parameters from various sources,

View File

@@ -0,0 +1,49 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef __BKE_EMPTY_H__
#define __BKE_EMPTY_H__
/** \file BKE_empty.h
* \ingroup bke
* \brief General operations for empties (object type).
*/
struct BoundBox;
struct Image;
struct ImBuf;
struct Object;
void BKE_empty_draw_type_set(struct Object *ob, const int value);
void BKE_empty_drawboundbox_get(const struct Object *ob, struct BoundBox *r_bb);
void BKE_empty_imbuf_get(
const struct Object *ob,
struct Image **r_ima, struct ImBuf **r_ibuf);
void BKE_empty_image_size_get_ex(
const struct Object *ob, struct Image *ima, struct ImBuf *ibuf,
float r_size_xy[2], float r_scale_xy[2]);
void BKE_empty_image_size_get(
const struct Object *ob,
float r_size_xy[2], float r_scale_xy[2]);
#endif /* __BKE_EMPTY_H__ */

View File

@@ -49,6 +49,8 @@ struct Lamp *localize_lamp(struct Lamp *la) ATTR_WARN_UNUSED_RESULT;
void BKE_lamp_make_local(struct Main *bmain, struct Lamp *la, const bool lib_local);
void BKE_lamp_free(struct Lamp *la);
void BKE_lamp_drawboundbox_get(const struct Lamp *la, struct BoundBox *r_bb);
void lamp_drivers_update(struct Scene *scene, struct Lamp *la, float ctime);
#ifdef __cplusplus

View File

@@ -147,9 +147,15 @@ struct BoundBox *BKE_boundbox_ensure_minimum_dimensions(
struct BoundBox *bb, struct BoundBox *bb_temp, const float epsilon);
struct BoundBox *BKE_object_boundbox_get(struct Object *ob);
void BKE_object_drawboundbox_get(
const struct Scene *scene, const struct Object *ob,
struct BoundBox *r_bb);
void BKE_object_boundbox_to_worldspace(
const struct Object *ob, const float pixelsize,
const struct BoundBox *in_localspace,
struct BoundBox *r_out_worldspace);
void BKE_object_dimensions_get(struct Object *ob, float vec[3]);
void BKE_object_dimensions_set(struct Object *ob, const float value[3]);
void BKE_object_empty_draw_type_set(struct Object *ob, const int value);
void BKE_object_boundbox_flag(struct Object *ob, int flag, const bool set);
void BKE_object_minmax(struct Object *ob, float r_min[3], float r_max[3], const bool use_hidden);
bool BKE_object_minmax_dupli(struct Scene *scene, struct Object *ob, float r_min[3], float r_max[3], const bool use_hidden);

View File

@@ -28,6 +28,7 @@
* \brief General operations for speakers.
*/
struct BoundBox;
struct Main;
struct Speaker;
@@ -37,4 +38,6 @@ struct Speaker *BKE_speaker_copy(struct Main *bmain, struct Speaker *spk);
void BKE_speaker_make_local(struct Main *bmain, struct Speaker *spk, const bool lib_local);
void BKE_speaker_free(struct Speaker *spk);
void BKE_speaker_drawboundbox_get(struct BoundBox *r_bb);
#endif

View File

@@ -102,6 +102,7 @@ set(SRC
intern/editmesh.c
intern/editmesh_bvh.c
intern/effect.c
intern/empty.c
intern/fcurve.c
intern/fluidsim.c
intern/fmodifier.c
@@ -229,6 +230,7 @@ set(SRC
BKE_editmesh.h
BKE_editmesh_bvh.h
BKE_effect.h
BKE_empty.h
BKE_fcurve.h
BKE_fluidsim.h
BKE_font.h

View File

@@ -57,6 +57,7 @@
#include "GPU_compositing.h"
/****************************** Camera Datablock *****************************/
void BKE_camera_init(Camera *cam)
@@ -169,6 +170,35 @@ int BKE_camera_sensor_fit(int sensor_fit, float sizex, float sizey)
return sensor_fit;
}
/**
* Even though our virtual cameras are infinite small points with some attributes,
* sometimes we need the bounding box that matches what the user sees.
*/
void BKE_camera_drawboundbox_get(const Scene *scene, const Object *ob, BoundBox *r_bb)
{
Camera *cam = ob->data;
float viewframe[4][3];
float min[3], max[3];
float dummy_asp[2];
float dummy_shift[2];
float dummy_drawsize;
float scale[3] = {1.0f, 1.0f, 1.0f};
BKE_camera_view_frame_ex(
scene, cam, cam->drawsize, false,
scale, dummy_asp, dummy_shift, &dummy_drawsize,
viewframe);
INIT_MINMAX(min, max);
for (int i = 0; i < 4; i++) {
minmax_v3v3_v3(min, max, viewframe[i]);
}
const float origin[3] = {0.0f};
minmax_v3v3_v3(min, max, origin);
BKE_boundbox_init_from_minmax(r_bb, min, max);
}
/******************************** Camera Params *******************************/
void BKE_camera_params_init(CameraParams *params)

View File

@@ -0,0 +1,182 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/blenkernel/intern/empty.c
* \ingroup bke
*/
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BKE_empty.h"
#include "BKE_image.h"
#include "BKE_object.h"
#include "DNA_object_types.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "MEM_guardedalloc.h"
void BKE_empty_draw_type_set(Object *ob, const int value)
{
ob->empty_drawtype = value;
if (ob->type == OB_EMPTY && ob->empty_drawtype == OB_EMPTY_IMAGE) {
if (!ob->iuser) {
ob->iuser = MEM_callocN(sizeof(ImageUser), "image user");
ob->iuser->ok = 1;
ob->iuser->frames = 100;
ob->iuser->sfra = 1;
ob->iuser->fie_ima = 2;
}
}
else {
if (ob->iuser) {
MEM_freeN(ob->iuser);
ob->iuser = NULL;
}
}
}
void BKE_empty_drawboundbox_get(const Object *ob, BoundBox *r_bb)
{
const float size = ob->empty_drawsize;
float min[3] = {0.0f};
float max[3] = {0.0f};
BLI_assert(ob->type == OB_EMPTY);
switch (ob->empty_drawtype) {
case OB_ARROWS:
min[0] = min[1] = -size * 0.08f;
copy_v3_fl(max, size);
break;
case OB_CIRCLE:
min[0] = min[2] = -size;
max[0] = max[2] = size;
break;
case OB_SINGLE_ARROW:
min[0] = min[1] = -size * 0.035f;
max[0] = max[1] = size * 0.035f;
max[2] = size;
break;
case OB_EMPTY_CONE:
min[0] = min[2] = -size;
max[0] = max[2] = size;
max[1] = size * 2.0f;
break;
case OB_EMPTY_IMAGE:
{
/* get correct image size */
float img_size[2], img_scale[2];
BKE_empty_image_size_get(ob, img_size, img_scale);
mul_v2_v2v2(max, img_size, img_scale);
/* apply offset */
float ofs[2];
mul_v2_v2v2(ofs, ob->ima_ofs, img_size);
mul_v2_v2(ofs, img_scale);
add_v2_v2(min, ofs);
add_v2_v2(max, ofs);
break;
}
default:
copy_v3_fl(min, -size);
copy_v3_fl(max, size);
break;
}
BKE_boundbox_init_from_minmax(r_bb, min, max);
}
/**
* \note Need to free \a r_ibuf using #BKE_image_release_ibuf.
*/
void BKE_empty_imbuf_get(const Object *ob, Image **r_ima, ImBuf **r_ibuf)
{
BLI_assert(ob->type == OB_EMPTY && ob->empty_drawtype == OB_EMPTY_IMAGE);
*r_ima = ob->data;
*r_ibuf = BKE_image_acquire_ibuf(*r_ima, ob->iuser, NULL);
if (*r_ibuf && ((*r_ibuf)->rect == NULL) && ((*r_ibuf)->rect_float != NULL)) {
IMB_rect_from_float(* r_ibuf);
}
}
void BKE_empty_image_size_get_ex(
const Object *ob, Image *ima, ImBuf *ibuf,
float r_size_xy[2], float r_scale_xy[2])
{
float sca_x = 1.0f;
float sca_y = 1.0f;
int ima_x, ima_y;
BLI_assert(ob->type == OB_EMPTY && ob->empty_drawtype == OB_EMPTY_IMAGE);
BLI_assert(r_size_xy || r_scale_xy);
/* Get the buffer dimensions so we can fallback to fake ones */
if (ibuf && ibuf->rect) {
ima_x = ibuf->x;
ima_y = ibuf->y;
}
else {
ima_x = 1;
ima_y = 1;
}
/* Get the image aspect even if the buffer is invalid */
if (ima) {
if (ima->aspx > ima->aspy) {
sca_y = ima->aspy / ima->aspx;
}
else if (ima->aspx < ima->aspy) {
sca_x = ima->aspx / ima->aspy;
}
}
/* Calculate Image scale */
const float scale = ob->empty_drawsize / max_ff((float)ima_x * sca_x, (float)ima_y * sca_y);
if (r_size_xy) {
r_size_xy[0] = ima_x;
r_size_xy[1] = ima_y;
}
if (r_scale_xy) {
r_scale_xy[0] = scale * sca_x;
r_scale_xy[1] = scale * sca_y;
}
}
void BKE_empty_image_size_get(const Object *ob, float r_size_xy[2], float r_scale_xy[2])
{
Image *ima = NULL;
ImBuf *ibuf = NULL;
BKE_empty_imbuf_get(ob, &ima, &ibuf);
BKE_empty_image_size_get_ex(ob, ima, ibuf, r_size_xy, r_scale_xy);
if (ibuf) {
BKE_image_release_ibuf(ima, ibuf, NULL);
}
}

View File

@@ -54,6 +54,7 @@
#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_object.h"
void BKE_lamp_init(Lamp *la)
{
@@ -237,3 +238,18 @@ void lamp_drivers_update(Scene *scene, Lamp *la, float ctime)
la->id.tag &= ~LIB_TAG_DOIT;
}
/**
* Get the visual bounding box of lamps, without things like direction indicator etc (we don't
* want this for selecting). Should match what #drawlamp draws (keep in sync!).
*/
void BKE_lamp_drawboundbox_get(const Lamp *la, BoundBox *r_bb)
{
const bool draw_outer = la->type != LA_HEMI &&
((la->mode & LA_SHAD_RAY) || ((la->mode & LA_SHAD_BUF) && (la->type == LA_SPOT)));
const float lamprad = (float)U.obcenter_dia * 1.5f + (draw_outer ? 3.0f : 0.0f);
const float min[3] = {-lamprad, -lamprad, -lamprad};
const float max[3] = {lamprad, lamprad, lamprad};
BKE_boundbox_init_from_minmax(r_bb, min, max);
}

View File

@@ -86,6 +86,7 @@
#include "BKE_curve.h"
#include "BKE_displist.h"
#include "BKE_effect.h"
#include "BKE_empty.h"
#include "BKE_fcurve.h"
#include "BKE_group.h"
#include "BKE_icons.h"
@@ -2310,6 +2311,62 @@ BoundBox *BKE_object_boundbox_get(Object *ob)
return bb;
}
/**
* For some cases we need the visual bounding box of objects that don't
* have real geometry, that are just infinite small points in space.
*/
void BKE_object_drawboundbox_get(
const Scene *scene, const Object *ob,
BoundBox *r_bb)
{
BoundBox *bb = BKE_object_boundbox_get((Object *)ob);
if (!bb) {
switch (ob->type) {
case OB_CAMERA:
BKE_camera_drawboundbox_get(scene, ob, r_bb);
break;
case OB_EMPTY:
BKE_empty_drawboundbox_get(ob, r_bb);
break;
case OB_LAMP:
BKE_lamp_drawboundbox_get(ob->data, r_bb);
break;
case OB_SPEAKER:
BKE_speaker_drawboundbox_get(r_bb);
break;
default:
break;
}
}
else {
*r_bb = *bb;
}
}
/**
* Transform a (draw-) bounding box from local into world space.
* \a in_localspace and *r_out_worldspace are allowed to be the same.
*
* \param pixelsize: Value of #ED_view3d_pixel_size.
*/
void BKE_object_boundbox_to_worldspace(
const Object *ob, const float pixelsize,
const BoundBox *in_localspace,
BoundBox *r_out_worldspace)
{
for (int i = 0; i < 8; i++) {
if (ob->type == OB_LAMP) {
/* for lamps, only use location and zoom independent size */
mul_v3_v3fl(r_out_worldspace->vec[i], in_localspace->vec[i], pixelsize);
add_v3_v3(r_out_worldspace->vec[i], ob->obmat[3]);
}
else {
mul_v3_m4v3(r_out_worldspace->vec[i], (float (*)[4])ob->obmat, in_localspace->vec[i]);
}
}
}
/* used to temporally disable/enable boundbox */
void BKE_object_boundbox_flag(Object *ob, int flag, const bool set)
{
@@ -2441,27 +2498,6 @@ void BKE_object_minmax(Object *ob, float min_r[3], float max_r[3], const bool us
}
}
void BKE_object_empty_draw_type_set(Object *ob, const int value)
{
ob->empty_drawtype = value;
if (ob->type == OB_EMPTY && ob->empty_drawtype == OB_EMPTY_IMAGE) {
if (!ob->iuser) {
ob->iuser = MEM_callocN(sizeof(ImageUser), "image user");
ob->iuser->ok = 1;
ob->iuser->frames = 100;
ob->iuser->sfra = 1;
ob->iuser->fie_ima = 2;
}
}
else {
if (ob->iuser) {
MEM_freeN(ob->iuser);
ob->iuser = NULL;
}
}
}
bool BKE_object_minmax_dupli(Scene *scene, Object *ob, float r_min[3], float r_max[3], const bool use_hidden)
{
bool ok = false;

View File

@@ -1156,15 +1156,15 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode)
static void pbvh_draw_BB(PBVH *bvh)
{
GPU_init_draw_pbvh_BB();
GPU_init_draw_boundbox();
for (int a = 0; a < bvh->totnode; a++) {
PBVHNode *node = &bvh->nodes[a];
GPU_draw_pbvh_BB(node->vb.bmin, node->vb.bmax, ((node->flag & PBVH_Leaf) != 0));
GPU_draw_boundbox(node->vb.bmin, node->vb.bmax, ((node->flag & PBVH_Leaf) != 0));
}
GPU_end_draw_pbvh_BB();
GPU_end_draw_boundbox();
}
static int pbvh_flush_bb(PBVH *bvh, PBVHNode *node, int flag)

View File

@@ -37,8 +37,10 @@
#include "BKE_library_query.h"
#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_object.h"
#include "BKE_speaker.h"
void BKE_speaker_init(Speaker *spk)
{
BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(spk, id));
@@ -91,3 +93,14 @@ void BKE_speaker_free(Speaker *spk)
{
BKE_animdata_free((ID *)spk, false);
}
void BKE_speaker_drawboundbox_get(BoundBox *r_bb)
{
const float maxrad = 0.5f;
const float zmin = -0.125f;
const float zmax = 0.25f * 2 - 0.125;
const float min[3] = {-maxrad, -maxrad, zmin};
const float max[3] = {maxrad, maxrad, zmax};
BKE_boundbox_init_from_minmax(r_bb, min, max);
}

View File

@@ -117,6 +117,7 @@ MINLINE void mul_v2_v2fl(float r[2], const float a[2], float f);
MINLINE void mul_v3_fl(float r[3], float f);
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f);
MINLINE void mul_v2_v2(float r[2], const float a[2]);
MINLINE void mul_v2_v2v2(float r[2], const float a[2], const float b[2]);
MINLINE void mul_v3_v3(float r[3], const float a[3]);
MINLINE void mul_v3_v3v3(float r[3], const float a[3], const float b[3]);
MINLINE void mul_v4_fl(float r[4], float f);

View File

@@ -431,6 +431,12 @@ MINLINE void mul_v2_v2(float r[2], const float a[2])
r[1] *= a[1];
}
MINLINE void mul_v2_v2v2(float r[2], const float a[2], const float b[2])
{
r[0] = a[0] * b[0];
r[1] = a[1] * b[1];
}
MINLINE void mul_v3_v3(float r[3], const float a[3])
{
r[0] *= a[0];

View File

@@ -122,6 +122,7 @@
#include "BKE_curve.h"
#include "BKE_depsgraph.h"
#include "BKE_effect.h"
#include "BKE_empty.h"
#include "BKE_fcurve.h"
#include "BKE_global.h" // for G
#include "BKE_group.h"
@@ -5514,7 +5515,7 @@ static void direct_link_object(FileData *fd, Object *ob)
ob->iuser = newdataadr(fd, ob->iuser);
if (ob->type == OB_EMPTY && ob->empty_drawtype == OB_EMPTY_IMAGE && !ob->iuser) {
BKE_object_empty_draw_type_set(ob, ob->empty_drawtype);
BKE_empty_draw_type_set(ob, ob->empty_drawtype);
}
ob->customdata_mask = 0;
@@ -7045,6 +7046,7 @@ static bool direct_link_screen(FileData *fd, bScreen *sc)
BLI_listbase_clear(&v3d->afterdraw_xraytransp);
v3d->properties_storage = NULL;
v3d->defmaterial = NULL;
v3d->bvhtree = NULL;
/* render can be quite heavy, set to solid on load */
if (v3d->drawtype == OB_RENDER)

View File

@@ -69,6 +69,7 @@
#include "BKE_DerivedMesh.h"
#include "BKE_displist.h"
#include "BKE_effect.h"
#include "BKE_empty.h"
#include "BKE_font.h"
#include "BKE_group.h"
#include "BKE_lamp.h"
@@ -797,7 +798,7 @@ static int object_empty_add_exec(bContext *C, wmOperator *op)
ob = ED_object_add_type(C, OB_EMPTY, NULL, loc, rot, false, layer);
BKE_object_empty_draw_type_set(ob, type);
BKE_empty_draw_type_set(ob, type);
BKE_object_obdata_size_init(ob, RNA_float_get(op->ptr, "radius"));
return OPERATOR_FINISHED;
@@ -862,7 +863,7 @@ static int empty_drop_named_image_invoke(bContext *C, wmOperator *op, const wmEv
ED_view3d_cursor3d_position(C, ob->loc, event->mval);
}
BKE_object_empty_draw_type_set(ob, OB_EMPTY_IMAGE);
BKE_empty_draw_type_set(ob, OB_EMPTY_IMAGE);
id_us_min(ob->data);
ob->data = ima;

View File

@@ -50,6 +50,7 @@ set(SRC
drawvolume.c
space_view3d.c
view3d_buttons.c
view3d_bvh.c
view3d_camera_control.c
view3d_draw.c
view3d_edit.c

View File

@@ -58,6 +58,7 @@
#include "BKE_DerivedMesh.h"
#include "BKE_deform.h"
#include "BKE_displist.h"
#include "BKE_empty.h"
#include "BKE_font.h"
#include "BKE_global.h"
#include "BKE_image.h"
@@ -633,50 +634,23 @@ void drawaxes(const float viewmat_local[4][4], float size, char drawtype)
/* Function to draw an Image on an empty Object */
static void draw_empty_image(Object *ob, const short dflag, const unsigned char ob_wire_col[4])
{
Image *ima = ob->data;
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, ob->iuser, NULL);
Image *ima = NULL;
ImBuf *ibuf = NULL;
float img_size[2], img_scale[2];
float ofs[2];
if (ibuf && (ibuf->rect == NULL) && (ibuf->rect_float != NULL)) {
IMB_rect_from_float(ibuf);
}
BKE_empty_imbuf_get(ob, &ima, &ibuf);
int ima_x, ima_y;
/* Get the buffer dimensions so we can fallback to fake ones */
if (ibuf && ibuf->rect) {
ima_x = ibuf->x;
ima_y = ibuf->y;
}
else {
ima_x = 1;
ima_y = 1;
}
float sca_x = 1.0f;
float sca_y = 1.0f;
/* Get the image aspect even if the buffer is invalid */
if (ima) {
if (ima->aspx > ima->aspy) {
sca_y = ima->aspy / ima->aspx;
}
else if (ima->aspx < ima->aspy) {
sca_x = ima->aspx / ima->aspy;
}
}
BKE_empty_image_size_get_ex(ob, ima, ibuf, img_size, img_scale);
/* Calculate the scale center based on object's origin */
float ofs_x = ob->ima_ofs[0] * ima_x;
float ofs_y = ob->ima_ofs[1] * ima_y;
mul_v2_v2v2(ofs, ob->ima_ofs, img_size);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
/* Calculate Image scale */
float scale = ob->empty_drawsize / max_ff((float)ima_x * sca_x, (float)ima_y * sca_y);
/* Set the object scale */
glScalef(scale * sca_x, scale * sca_y, 1.0f);
glScale2fv(img_scale);
if (ibuf && ibuf->rect) {
const bool use_clip = (U.glalphaclip != 1.0f);
@@ -694,7 +668,7 @@ static void draw_empty_image(Object *ob, const short dflag, const unsigned char
glColor4fv(ob->col);
/* Draw the Image on the screen */
glaDrawPixelsTex(ofs_x, ofs_y, ima_x, ima_y, GL_RGBA, GL_UNSIGNED_BYTE, zoomfilter, ibuf->rect);
glaDrawPixelsTex(ofs[0], ofs[1], img_size[0], img_size[1], GL_RGBA, GL_UNSIGNED_BYTE, zoomfilter, ibuf->rect);
glDisable(GL_BLEND);
@@ -710,16 +684,18 @@ static void draw_empty_image(Object *ob, const short dflag, const unsigned char
/* Calculate the outline vertex positions */
glBegin(GL_LINE_LOOP);
glVertex2f(ofs_x, ofs_y);
glVertex2f(ofs_x + ima_x, ofs_y);
glVertex2f(ofs_x + ima_x, ofs_y + ima_y);
glVertex2f(ofs_x, ofs_y + ima_y);
glVertex2fv(ofs);
glVertex2f(ofs[0] + img_size[0], ofs[1]);
glVertex2f(ofs[0] + img_size[0], ofs[1] + img_size[1]);
glVertex2f(ofs[0], ofs[1] + img_size[1]);
glEnd();
/* Reset GL settings */
glPopMatrix();
BKE_image_release_ibuf(ima, ibuf, NULL);
if (ibuf && ibuf->rect) {
BKE_image_release_ibuf(ima, ibuf, NULL);
}
}
static void circball_array_fill(float verts[CIRCLE_RESOL][3], const float cent[3], float rad, const float tmat[4][4])
@@ -1170,6 +1146,10 @@ static void draw_transp_sun_volume(Lamp *la)
}
#endif
/**
* Note: BKE_lamp_drawboundbox_get tries to give the visual boundbox of what's drawn here (without things like
* sun direction indicator etc). If something is changed here that might influence the boundbox, keep it in sync!
*/
static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
const char dt, const short dflag, const unsigned char ob_wire_col[4], const bool is_obact)
{

View File

@@ -432,6 +432,10 @@ static void view3d_free(SpaceLink *sl)
MEM_freeN(vd->fx_settings.ssao);
if (vd->fx_settings.dof)
MEM_freeN(vd->fx_settings.dof);
if (vd->bvhtree) {
view3d_objectbvh_free(vd);
}
}

View File

@@ -0,0 +1,144 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/editors/space_view3d/view3d_bvh.c
* \ingroup spview3d
*/
#include "BKE_DerivedMesh.h"
#include "BKE_object.h"
#include "BLI_kdopbvh.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_view3d_types.h"
#include "GPU_buffers.h"
#include "MEM_guardedalloc.h"
#include "view3d_intern.h" /* own include */
static void bvh_objects_insert(View3D *v3d, const RegionView3D *rv3d, const Scene *scene)
{
Object *ob;
BoundBox bb;
int i = 0;
for (Base *base = scene->base.first; base; base = base->next) {
ob = base->object;
if (BASE_SELECTABLE(v3d, base)) {
BKE_object_drawboundbox_get(scene, ob, &bb);
BKE_object_boundbox_to_worldspace(ob, ED_view3d_pixel_size(rv3d, ob->obmat[3]), &bb, &bb);
BLI_bvhtree_insert(v3d->bvhtree, i++, &bb.vec[0][0], 8);
}
else {
// printf("Not selectable: %s\n", base->object->id.name + 2);
}
}
}
void view3d_objectbvh_rebuild(View3D *v3d, const RegionView3D *rv3d, const Scene *scene)
{
BVHTree *bvhtree = v3d->bvhtree;
if (bvhtree) {
view3d_objectbvh_free(v3d);
}
v3d->bvhtree = bvhtree = BLI_bvhtree_new(BLI_listbase_count(&scene->base), FLT_EPSILON, 2, 8);
bvh_objects_insert(v3d, rv3d, scene);
BLI_bvhtree_balance(bvhtree);
}
void view3d_objectbvh_free(View3D *v3d)
{
BLI_bvhtree_free(v3d->bvhtree);
}
Base *view3d_objectbvh_raycast(Scene *scene, View3D *v3d, ARegion *ar, const int mval[2])
{
RegionView3D *rv3d = ar->regiondata;
BVHTreeNearest nearest = {.index = -1, .dist_sq = FLT_MAX};
const float mval_fl[2] = {mval[0], mval[1]};
float ray_start[3] = {0}, ray_normal[3] = {0};
ED_view3d_win_to_ray(ar, v3d, mval_fl, ray_start, ray_normal, true);
BLI_bvhtree_find_nearest_to_ray(v3d->bvhtree, ray_start, ray_normal, true, NULL, &nearest, NULL, NULL);
/* TODO more refined geometry check */
/* distance threshold */
const float dist_px = sqrtf(nearest.dist_sq) / ED_view3d_pixel_size(rv3d, nearest.co);
if (dist_px > SELECT_DIST_THRESHOLD) {
return NULL;
}
BoundBox bb;
int i = 0;
Base *base;
for (base = scene->base.first; base; base = base->next) {
if (BASE_SELECTABLE(v3d, base)) {
BKE_object_drawboundbox_get(scene, base->object, &bb);
if (i == nearest.index) {
break;
}
i++;
}
}
if (base) {
// printf("Select: %s\n", base->object->id.name + 2);
}
return base;
}
static void bvh_draw_boundbox(const BVHTreeAxisRange *bounds, const bool is_leaf)
{
float min[3] = {bounds[0].min, bounds[1].min, bounds[2].min};
float max[3] = {bounds[0].max, bounds[1].max, bounds[2].max};
GPU_draw_boundbox(min, max, is_leaf);
}
static bool bvh_draw_boundbox_parent_cb(const BVHTreeAxisRange *bounds, void *UNUSED(userdata))
{
bvh_draw_boundbox(bounds, false);
return true;
}
static bool bvh_draw_boundbox_leaf_cb(const BVHTreeAxisRange *bounds, int UNUSED(index), void *UNUSED(userdata))
{
bvh_draw_boundbox(bounds, true);
return true;
}
static bool bvh_walk_order_cb(const BVHTreeAxisRange *UNUSED(bounds), char UNUSED(axis), void *UNUSED(userdata))
{
return true;
}
void view3d_bvh_draw_boundboxes(const View3D *v3d)
{
GPU_init_draw_boundbox();
BLI_bvhtree_walk_dfs(v3d->bvhtree, bvh_draw_boundbox_parent_cb, bvh_draw_boundbox_leaf_cb, bvh_walk_order_cb, NULL);
GPU_end_draw_boundbox();
}

View File

@@ -3900,6 +3900,10 @@ static void view3d_main_region_draw_objects(const bContext *C, Scene *scene, Vie
/* main drawing call */
view3d_draw_objects(C, scene, v3d, ar, grid_unit, true, false, do_compositing ? rv3d->compositor : NULL);
// if (G.debug_value == 14) {
view3d_bvh_draw_boundboxes(v3d);
// }
/* post process */
if (do_compositing) {
GPU_fx_do_composite_pass(rv3d->compositor, rv3d->winmat, rv3d->is_persp, scene, NULL);
@@ -4047,6 +4051,11 @@ void view3d_main_region_draw(const bContext *C, ARegion *ar)
render_border = ED_view3d_calc_render_border(scene, v3d, ar, &border_rect);
clip_border = (render_border && !BLI_rcti_compare(&ar->drawrct, &border_rect));
if (!scene->obedit) {
ED_view3d_update_viewmat(scene, v3d, ar, NULL, NULL); /* XXX */
view3d_objectbvh_rebuild(v3d, ar->regiondata, scene);
}
/* draw viewport using opengl */
if (v3d->drawtype != OB_RENDER || !view3d_main_region_do_render_draw(scene) || clip_border) {
view3d_main_region_draw_objects(C, scene, v3d, ar, &grid_unit);

View File

@@ -50,6 +50,9 @@ struct wmOperatorType;
struct wmWindowManager;
struct wmKeyConfig;
/* Distance */
#define SELECT_DIST_THRESHOLD 14 /* px */
/* drawing flags: */
enum {
DRAW_PICKING = (1 << 0),
@@ -285,6 +288,13 @@ void VIEW3D_OT_snap_cursor_to_center(struct wmOperatorType *ot);
void VIEW3D_OT_snap_cursor_to_selected(struct wmOperatorType *ot);
void VIEW3D_OT_snap_cursor_to_active(struct wmOperatorType *ot);
void view3d_objectbvh_rebuild(View3D *v3d, const RegionView3D *rv3d, const Scene *scene);
void view3d_bvh_update(View3D *v3d, const Scene *scene);
void view3d_objectbvh_free(View3D *v3d);
Base *view3d_objectbvh_raycast(Scene *scene, View3D *v3d, ARegion *ar, const int mval[]);
void view3d_bvh_draw_boundboxes(const View3D *v3d);
/* space_view3d.c */
ARegion *view3d_has_buttons_region(ScrArea *sa);
ARegion *view3d_has_tools_region(ScrArea *sa);

View File

@@ -98,6 +98,8 @@
#include "view3d_intern.h" /* own include */
#define USE_BVH_SELECT
float ED_view3d_select_dist_px(void)
{
return 75.0f * U.pixelsize;
@@ -1380,7 +1382,11 @@ Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2])
return basact;
}
#ifdef USE_BVH_SELECT
static void UNUSED_FUNCTION(deselect_all_tracks)(MovieTracking *tracking)
#else
static void deselect_all_tracks(MovieTracking *tracking)
#endif
{
MovieTrackingObject *object;
@@ -1461,6 +1467,15 @@ static bool ed_object_select_pick(
}
}
else {
#ifdef USE_BVH_SELECT
basact = view3d_objectbvh_raycast(scene, v3d, ar, mval);
/* TODO more advanced selection methods */
// WM_event_add_notifier(C, NC_MOVIECLIP | ND_SELECT, track);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
UNUSED_VARS(hits);
#else
unsigned int buffer[MAXPICKBUF];
bool do_nearest;
@@ -1563,6 +1578,7 @@ static bool ed_object_select_pick(
basact = NULL;
}
}
#endif /* USE_BVH_SELECT */
}
/* so, do we have something selected? */

View File

@@ -258,10 +258,10 @@ void GPU_update_grid_pbvh_buffers(GPU_PBVH_Buffers *buffers, struct CCGElem **gr
void GPU_draw_pbvh_buffers(GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial,
bool wireframe, bool fast);
/* debug PBVH draw*/
void GPU_draw_pbvh_BB(float min[3], float max[3], bool leaf);
void GPU_end_draw_pbvh_BB(void);
void GPU_init_draw_pbvh_BB(void);
/* boundbox drawing */
void GPU_draw_boundbox(float min[3], float max[3], bool is_leaf);
void GPU_end_draw_boundbox(void);
void GPU_init_draw_boundbox(void);
bool GPU_pbvh_buffers_diffuse_changed(GPU_PBVH_Buffers *buffers, struct GSet *bm_faces, bool show_diffuse_color);

View File

@@ -2032,8 +2032,11 @@ void GPU_free_pbvh_buffer_multires(GridCommonGPUBuffer **grid_common_gpu_buffer)
}
}
/* debug function, draws the pbvh BB */
void GPU_draw_pbvh_BB(float min[3], float max[3], bool leaf)
/**
* Function to draw a boundbox based on \a min and \a max coordinates. Useful for BVH tree debugging.
* \param is_leaf: For BVH trees, color leafs different than parents.
*/
void GPU_draw_boundbox(float min[3], float max[3], bool is_leaf)
{
const float quads[4][4][3] = {
{
@@ -2065,7 +2068,7 @@ void GPU_draw_pbvh_BB(float min[3], float max[3], bool leaf)
},
};
if (leaf)
if (is_leaf)
glColor4f(0.0, 1.0, 0.0, 0.5);
else
glColor4f(1.0, 0.0, 0.0, 0.5);
@@ -2074,7 +2077,7 @@ void GPU_draw_pbvh_BB(float min[3], float max[3], bool leaf)
glDrawArrays(GL_QUADS, 0, 16);
}
void GPU_init_draw_pbvh_BB(void)
void GPU_init_draw_boundbox(void)
{
glPushAttrib(GL_ENABLE_BIT);
glDisable(GL_CULL_FACE);
@@ -2084,7 +2087,7 @@ void GPU_init_draw_pbvh_BB(void)
glEnable(GL_BLEND);
}
void GPU_end_draw_pbvh_BB(void)
void GPU_end_draw_boundbox(void)
{
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glPopAttrib();

View File

@@ -238,6 +238,9 @@ typedef struct View3D {
float stereo3d_volume_alpha;
float stereo3d_convergence_alpha;
/** Viewport BVH tree (runtime only). Used for BVH based selection. */
struct BVHTree *bvhtree;
/* Previous viewport draw type.
* Runtime-only, set in the rendered viewport toggle operator.
*/

View File

@@ -183,6 +183,7 @@ EnumPropertyItem rna_enum_object_axis_items[] = {
#include "BKE_curve.h"
#include "BKE_depsgraph.h"
#include "BKE_effect.h"
#include "BKE_empty.h"
#include "BKE_global.h"
#include "BKE_key.h"
#include "BKE_object.h"
@@ -487,7 +488,7 @@ static void rna_Object_empty_draw_type_set(PointerRNA *ptr, int value)
{
Object *ob = (Object *)ptr->data;
BKE_object_empty_draw_type_set(ob, value);
BKE_empty_draw_type_set(ob, value);
}
static EnumPropertyItem *rna_Object_collision_bounds_itemf(bContext *UNUSED(C), PointerRNA *ptr,