Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VisibilityNotifier - add max_distance feature #61544

Merged
merged 1 commit into from
Jun 10, 2022

Conversation

lawnjelly
Copy link
Member

@lawnjelly lawnjelly commented May 30, 2022

Enables turning off objects by distance to the camera in addition to testing whether they are in the view frustum.

vis_notifier

2022-05-30.17-57-31.mp4

Notes

  • This is something I've been meaning to add since discussing with Miziziziz when testing WroughtFlesh, in an open world game, it is particularly useful option to be able to throttle animation etc by distance.
  • This also works with VisibilityEnabler because it is derived from VisibilityNotifier. It can also be used to turn off process / physics_process / AI etc.
  • Works using the AABB center, so needs to keep track of this. Could be less complex using the VisibilityNotifier node origin, but users may place the AABB off axis.
  • There is currently no hysteresis (VisibilityNotifier doesn't have hysteresis for any of the camera planes). I'm not yet sure whether it needs hysteresis, but it could easily be put in later if it proves useful.
  • I've added a "first added" counter to force allow it to update initially. This ensures that animations (and possibly physics?) are allowed to update for at least a frame to ensure animation is reasonable and characters don't appear in the distance in the "T pose". This is hard coded to 1, but could possibly be exposed / changed later if it would be useful for physics.
  • It might be nice if the animation picked up where it left off, as the example animation shows there can be a glitch where it re-enters range. But this is really outside the scope of the PR.

@Zireael07
Copy link
Contributor

Whoa, nice usecase with stopping animations <3

@lawnjelly lawnjelly force-pushed the vis_notifier_max_dist branch 2 times, most recently from 83f9a46 to e1a77e6 Compare May 31, 2022 08:49
@lawnjelly lawnjelly marked this pull request as ready for review May 31, 2022 08:52
@lawnjelly lawnjelly requested review from a team as code owners May 31, 2022 08:52
@lawnjelly lawnjelly force-pushed the vis_notifier_max_dist branch from e1a77e6 to 3722088 Compare June 8, 2022 06:36
@lawnjelly
Copy link
Member Author

lawnjelly commented Jun 8, 2022

@clayjohn I added the support for ortho cameras, with this snippet here:

		Plane near_plane;

		for (Map<Camera *, CameraData>::Element *E = cameras.front(); E; E = E->next()) {
			pass++;

			// prepare camera info
			Camera *c = E->key();
			Transform cam_xform = c->get_global_transform();
			Vector3 cam_pos = cam_xform.origin;
			bool cam_is_ortho = c->get_projection() == Camera::PROJECTION_ORTHOGONAL;
			if (cam_is_ortho) {
				near_plane = Plane(cam_xform.origin, -cam_xform.basis.get_axis(2).normalized());
			}

			Vector<Plane> planes = c->get_frustum();

@@ -160,6 +169,31 @@ struct SpatialIndexer {
			for (int i = 0; i < culled; i++) {
				//notifiers in frustum

				// check and remove notifiers that have a max range
				VisibilityNotifier &nt = *ptr[i];
				if (nt.is_max_distance_active()) {
					bool distance_reject = false;
					if (!cam_is_ortho) {
						Vector3 offset = nt.get_world_aabb_center() - cam_pos;
						if ((offset.length_squared() >= nt.get_max_distance_squared()) && !nt.inside_max_distance_leadin()) {
							distance_reject = true;
						}
					} else {
						real_t dist = near_plane.distance_to(nt.get_world_aabb_center());
						if ((dist >= nt.get_max_distance()) && !nt.inside_max_distance_leadin()) {
							distance_reject = true;
						}
					}

					if (distance_reject) {
						// unordered remove
						cull.set(i, cull[culled - 1]);
						culled--;
						i--;
						continue;
					}
				}

However on reflection, I'm not sure whether we should support the distance cutoff in ortho cameras, or just ignore the max distance completely in this situation.

The problem is that with an ortho camera, the distance from the near plane has no effect on the screen size of the object, so doesn't make quite as much sense to turn it off and on (from a visual perspective).

On the other hand, if we don't use distance here, then if e.g. a game has a main perspective and a small ortho overview camera, the overview camera will always cause the VisibilityNotifiers to report the objects as in view, and they will never throttle down. But maybe this is overthinking it, and this is a game design issue.

What do you think?

The PR will currently ignore ortho cameras but I'll retain a backup of the switching version above depending which we choose.

@lawnjelly lawnjelly force-pushed the vis_notifier_max_dist branch from 3722088 to 409d162 Compare June 8, 2022 06:52
@Calinou
Copy link
Member

Calinou commented Jun 8, 2022

However on reflection, I'm not sure whether we should support the distance cutoff in ortho cameras, or just ignore the max distance completely in this situation.

Last time I checked, the implementation of the light LOD system in master (and GeometryInstance distance fade in master) does take orthogonal cameras into account, so lights fade out when the camera zooms out. This may be better achieved with the orthogonal size property though.

@lawnjelly
Copy link
Member Author

Last time I checked, the implementation of the light LOD system in master (and GeometryInstance distance fade in master) does take orthogonal cameras into account, so lights fade out when the camera zooms out. This may be better achieved with the orthogonal size property though.

Yes I think for lights it can make sense to fade. But for this max_distance for VisibilityNotifier, it could just mean objects stop animating + moving around once they get a certain distance, irrespective of their screen size metric (they could be taking up the whole screen when this happens with an ortho camera). With a perspective camera this change in behaviour can be worth it for the savings in performance, as the objects screen size will usually be small when you would choose to use this, and you are less likely to notice it / find it jarring.

This may be less of a problem if we could fix the animation popping. To solve animation popping I'm thinking in terms of either fading in from the previous state, or even, just not progress the animation timeline when hidden by a VisibilityNotifier (or at least by the distance version).

Still there may be no right or wrong answer here. I suppose we could make the ortho behaviour selectable (on the VisibilityNotifier, or even on the camera). But we could choose to add it for perspective cameras first, then decide based on feedback whether we should offer an ortho mode. 🤔

Copy link
Member

@clayjohn clayjohn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lawnjelly I agree, lets disable this for orthogonal cameras and then see if there is user demand.

doc/classes/VisibilityNotifier.xml Outdated Show resolved Hide resolved
Enables turning off objects by distance to the camera in addition to testing whether they are in the view frustum.
@lawnjelly lawnjelly force-pushed the vis_notifier_max_dist branch from 409d162 to 0c5a424 Compare June 9, 2022 10:38
@akien-mga akien-mga modified the milestones: 3.x, 3.5 Jun 10, 2022
@akien-mga akien-mga merged commit a9e966c into godotengine:3.x Jun 10, 2022
@akien-mga
Copy link
Member

Thanks!

@lawnjelly lawnjelly deleted the vis_notifier_max_dist branch June 10, 2022 09:13
@Zireael07
Copy link
Contributor

No corresponding PR for master (I just noticed it's not in alpha 13 and started triple checking)???

@lawnjelly
Copy link
Member Author

lawnjelly commented Aug 2, 2022

No corresponding PR for master (I just noticed it's not in alpha 13 and started triple checking)???

I'll have a look at doing one for master. 👍

EDIT: Turns out the VisibilityNotifier system is completely different in master (it is done in renderer_scene_cull rather than World), so it will have to wait until I am familiar with the renderer, or might be done quicker by someone else already familiar with the renderer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants