God yes, coming from decades in commercial software where it’s possible to do this, I cringe at the thought of it, because it’s incredibly fragile and prone to breaking. It’s very bad practice which generally only people who are new to scripting resort to.
This is part of why I started this thread. I’m relatively new to Blender, and so am bumping my way in the dark, and I felt like doing it this way was exactly the same sort of thing. It’s a bit shocking to hear that there isn’t an alternative. E.g., the selection-by-looping-specific-components approach. It is exactly what I came up with, myself, but it felt so limited, covoluted, and wrong, that I figured there had to be another way.
This is so much like my dive in to Blender. Right away I couldn’t stand how clunky selection behavior was in general so I set out looking for way to make it behave in a way that felt more intuitive and comfortable to me. I ran in to a lot of the issues you’re talking about where just getting Blender to tell you what’s selected became a massive headache.
I basically started writing my own selection operators in python and got decently far along before 2.8 came along and broke all my scripts. I started re-writing them for 2.8 but then they’d get broken again.
Then I realized that writing these operators for objects and bmesh was not enough because there’s completely new operators for every different object types like curves, lights, armatures. Nothing’s unified. And behaviors are inconsistent from one object type to the next.
It became such a massive undertaking I just gave up.
This sounds quite familiar to me. I wrote some pretty simple stuff for 2.80. It was broken in 2.83.
Separately, I wrote some other simple stuff for 2.83. It was broken in 2.9x.
This thread made me think that I needed to do the same as you–write my own generic, universal selection operator so I can at least approach something like a ls -sl level of function. But of course, if everything’s going to change massively on each point release, it’s wasted effort.
Yep, this is kind of where I got off the bus. I poured so many hours in just to have all the work blown to bits over and over it killed all my motivation to keep going.
I get that it’s a massive and badly needed overhaul for Blender and code changes are bound to break all kinds of things, but it just never felt like it was safe to try and move forward. And I was too unsatisfied with Blender’s selection design to keep pursuing it. I still like to follow development, though.
I’d describe it more as: I am looking for a basic utility function. If this doesn’t exist, okay–and I figure there must be an overriding reason for the lack, because it’s far more basic than many features which the applicaiton already possesses.
Do you mean via C? If not, how?
I could do this, but whatever I write will be crippled by my inexperience with the platform. Because it’s such a basic function, I will assume that others like @andyvandalsem will have already done this, and perhaps in such a way that point releases prioritise keeping it functioning–if Maya or Max or Houdini shipped without a functional concise selection reporting function, every 3D shop on the planet would grind to a halt. So having a platform newbie build this wouldn’t make much sense, if it’s to be included as a core function, as it’s likely to break between versions.
This sounds like a good way to approach it.
Some code is above–and this is specific to vertices on a specific mesh in a specific UI context.
How it might ideally function would be as a single encapsulating command, which doesn’t care about component or object type or UI context.
There are a tonne of ways to do it, the more featureful of which would get fairly involved.
In its most rudimentary form, it’d be bpy.utils.get_selection(), probably with filters for object types (meshes, components, transforms, etc), and for returning either strings (where appropriate) or objects.
By looping over data and checking the select attribute.
When writing abstractions it often ends up not being as basic as you might think, you end up making assumptions about what the caller wants, which then need to be configurable to be used in different scenarios.
Script authors then need to become familier with the API abstraction and may run into situations it doesn’t support very well or figure how to extend the abstraction… what it’s limits are … etc.
What if the caller wants vertices even when in face-mode?
What if the caller wants only selected faces with valid UV coordinates.
How to access the object matrix of the vertices when multiple objects are in edit-mode?
How to handle multiple object instances of the same edit-mode data (return them multiple times or only once?)
How to handle mixing mesh selection modes vert/edge/face - return multiple elements when more than one is enabled?
How to access selected object (and not selected nodes, … files … UV’s etc, when other space-types are active).
How to differentiate between selected objects in local-view from selected objects in non-local 3D views?
Would the “selection” access have equivalent accessors for “visible”, “visible_editable”, “hidden” … even “user-defined” ?
… Of course all of this can be solved, everything can be made into an option - I assume other applications manage these kinds of issues, just noting that it’s not necessarily basic to write this kind of an API, unless it has limited defaults.
I rather see a full working MVP (a simple add-on for example) that does something useful, showing how poor the API is at performing the task. Otherwise it’s artificial and not necessarily so obvious what the issue is.
Do all selectable scene data have a .select attribute? I don’t think they do. Is it always available for query (and returning correctly), or is it context-dependant? I don’t think it is.
Yes. I’ve written plenty of these over the years. The best approach is to make the simplest set of features possible, and build from there, where necessary. However, basic != simple. Basic in the sense, of, a minimal set of API utility functions in a 3D DCC application, in 2021 (or in the case of selection, 2005ish).
A selection query function should not fall to a script. That is inappropriate. It’s a core application method which should be part of the source, and required to function predictably across minor and major releases. In one popular software application, the same code (which consists of 6 characters) that queried selection in 1998 still functions now.
Mode should be irrelevant. This issue is part of why this post exists.
Filtering beyond reporting the selection list is an additional feature, outside scope.
Again, this issue is core to this thread. It shouldn’t matter. This is part of the problem. Whatever reports the selection list shouldn’t take mode into account.
Don’t handle modes. Whatever’s selected is reported. Selection mode is irrelevant. This type of function isn’t really for use with the UI anyway.
Report the list of selected data. Ignore the space type. If it’s in memory and selected (that is, if a user would see the selection while traversing the space type), report it. Adding filtering for space types might be of use as an additional feature, but again, outside scope.
These terms I am not familiar with, but I expect that you do not take this into account. Report the selection.
No, as these aren’t in the scope of ‘what’s selected’. If you have a list of what’s selected, your task of filtering for these additional attributes is already greatly simplified.
I can’t make an MVP because I am not a seasoned Blender developer. I’ve written some utilities for things I am doing, and an alarming proportion of them have been broken by point releases, and this is entirely in the 2.80+ era. This doesn’t inspire confidence that my work is valued enough to make sure that API functions persist across releases, and it points to this type of method necessarily being integrated into the core codebase, to protect it from this type of breakage.
The issue is far less how the API might be performing the task than how difficult it is for someone to harness the API to perform the task–I’d gladly give up some efficiency in this sphere just to be able to do it generically, which I currently can’t.
While no ill intent is meant, you’re basically saying that Blender should behave differently, without learning how Blender currently works. Further you’re not interested to provide a concrete example of the problems you hint at.
It seems like you put areas of the Python API in the too hard basket. I’d suggest you ask questions about tasks you think should be simple on stackexchange, collect some useful examples that help you understand the API, .
I might be. Or I might be looking for functionality that a long career in CG has informed me should be present in a 3D application. Selection matters, especially in an application where so many operations are selection-dependant.
This thread is full of them. I clearly haven’t explained myself well enough. I haven’t been hinting but stating straight out:
(from what I can tell) there’s no generic ‘get selection’ method which functions independant of UI state or object/component type.
I am not sure how much more concrete I can be here. If this still isn’t clear enough, let me know.
Pointing out that something is missing or designed badly isn’t saying it’s “too hard”, it’s saying that it’s missing or designed badly. Those aren’t the same. Sure you can build a car with octagonal wheels, but why would you? I’ve tried to give the benefit of the doubt here, hoping that someone could explain why this is missing, but so far no one has. Maybe there’s a reason the wheels are octagonal; but I don’t know what that reason may be. I’d hate to think that the Blender python API is designed in a vacuum, ignoring common features, after all. I’m also not saying that there aren’t brilliant features as well. Saying that the wheels are octagonal doesn’t mean that the leather on the seats isn’t super supple.
When I went to stack exchange, they told me to come here. When I came here, they told me to go to stack exchange. Both places also told me to go to blender.chat, where I was also told to come here and go to stack exchange. The circle is complete.
IMO stackexchange isn’t a forum (in fact, I was literally told this when I tried to treat it like one), and this is a topic for a development forum: Is there something like bpy.utilities.get_selection()? Why hasn’t it been created, if not? A developer in this very thread said they tried to implement their own solution, but it was broken by changes to the API. This function should be impervious to such changes.
Every developer I know who I’ve told about this over the past couple weeks can’t believe that this is the status quo. And I am inclined to agree: maybe there’s something I am not seeing, how could Blender possibly exist in its current feature filled form without being able to query selection?
You’ve said this multiple times now and I hate to be the bearer of bad news, but there isn’t. It’s natural for our brains to try and find rationality when presented with an irrational situation but there is none to be found here.
If I had to guess, once ‘good enough’ MVP API calls were added there was no impetus to improve the situation. Like, yeah sure you can usually get what you’re after, but it’s spread across 5 different places in a sub-optimal way that foists a large amount of work onto the python user. Blender’s python API to me feels like you’re given a tub full of small LEGO pieces or individual atoms and you’re expected to do all the heavy lifting and build everything yourself instead of providing improved data access and convenience functions.
As another example Blender has no function for ‘return object or component nearest to cursor’. While this could be a one-liner invoked in python with a few parameters (like depth or search radius around the cursor), instead you’re expected to build an entire unwieldy raycast function comprising dozens of lines of code yourself (see the operator_modal_view3d_raycast.py template that ships with Blender) but you also can’t raycast onto objects that aren’t a mesh type! As far as I know the only way to get, for example, a light in object mode or a curve point in edit mode, is to invoke view3d.select and pass the mouse coordinates, but this has its own problems: This actually alters the scene selection, rather than simply reporting back what’s under the cursor, and then there’s the limited functionality and the hard-coded selection accuracy of view3d.select as mentioned by Andy.
Out of curiosity, in python my_selection = [v for v in bm.verts if v.select] takes ~0.42 seconds on a triangulated 2.9 million vertex photogrammetry mesh (at least on my hardware). That’s nearly half a second just to find out what’s selected, without doing anything else in the script. Could the speed be materially different if Blender internally maintained its own list (analogous to bm.select_history but for all selected verts, not just some of them) that could be queried like my_selection = bm.selected_verts or is the python loop basically on par with how fast Blender could maintain such a list with C?
The hardcoded hitbox is a massive 28 x 28 pixels! You could click your screen and select an object on a computer 3 city blocks away!
Yes, this is exactly what I had to do. Alter the selection, compare it to the previous selection, then either restore selection to previous or update the selection based on comparison results. Because there’s no way to easily find out what’s near the cursor. And that wound up being a lot of code to do what I thought would be a pretty basic thing.
Your questions could be handled at different levels, depending on use of the existing API, or discussing changes / improvements. I suggested stackexchange to get answers for how to use the current API.
In this case Python won’t be reliably fast.
Of course it’s nice to be fast if you only have a small selection, however if most items are selected it’s still going to be slow dealing with those items once they have been returned.
This moves the bottleneck to whatever the next step would be that iterates over items in Python. Once you have millions of vertices in a list and want to do some-operation fast, you will want optimized functions that avoid looping over elements in Python for that too.
Instead of handling this piecemeal, this is something that should be handled in a design, the conclusion may even be that Python is not a good fit for this kind of task too. Or that an API can be written that handles this, but it’s limited to fewer operations.
This would be useful & could be supported, not sure when there would be time for this, but created design task for it.
Sure, and I really do appreciate the attention you’ve given the matter here. I appreciate Blender in general–I think it’s amazing and I hope that my criticism of one aspect doesn’t negate from that. It’s the amazingness which has me befuddled here–if it were crap, I wouldn’t be as surprised by this aspect.
At the risk of stomping the horse into the centre of the Earth, this thread isn’t about “how to discover the selection”. I can do that, and other posters have confirmed that yes, I am doing it ‘right’ more or less, along with providing variations on the method. This thread is about “in order to discover the selection, I am doing a lot of things which I wouldn’t expect to do…is this right, and if so, can it be changed, and if not why not, and by the way does blender even have a concept of selection”.
All of this has been answered, more or less, which I appreciate, too.
Yeah if you need this level of performance, generally a Python API isn’t the way to go, in other applications either.
This is what I am going to do: write a wee module for reporting selection generically and simply. If it breaks with a new release, I will come back here, and you all can point out everything I did wrong.
Thanks, great analogy, and I’d add that in this scenario, point releases seem to subtly shift the shape of some of those little connecting nurnies on top of some of the blocks…so your puzzle won’t fit together anymore. I’ve dealt with this type of thing plenty of times, and I am comfortable doing it, but I wanted to have a discussion about the status quo before jumping in, and also test the room on “how likely is it that whatever I do will get broken by a point release” (very likely), before I did so.
There are many assumptions behind this statement that would need unpacking since I’m not sure what you expect or how you might want it changed. To understand this I would need some clear examples. Glad to hear you’re looking into this.
Note that in Blender 2.7x object selection/layers was much simpler. 2.8x object layers became more flexible but more complicated too, at the user level it can be managed from the outliner, but from Python managing collections can get a bit involved.
The Python API mirrors Blender’s internal structure, while that’s both a pro & a con, we can always expose higher level API’s that make things more convenient for script authors.