Linecast cost?

I’m trying to optimize a scene. Right now, there are too many objects on screen and the framerate is suffering considerably as a result. However, many of the objects onscreen are in other rooms not viewable from the camera’s current location. To combat this, I am considering setting up a script using physics.linecast to determine if any of my collision meshes for the walls are between the object and the camera. If so, the renderer is disabled for the object.

Below is a simple top-down example of what I’m working with. With the default setup, the purple object is not within the field of view of the camera and therefore is not rendered. However, both the green and blue objects are within view and get rendered. The green object is behind a wall, so I don’t want to render it. I could put the following script on all the colored objects:

function Update () {
if (Physics.Linecast (transform.position, camera.position)) {
renderer.enabled = false;
}
else
renderer.enabled = true;
}

I have no idea about the processing cost of Physics.Linecast. With a large volume of objects all casting lines to the camera at all times, do you think a setup like this be likely to improve framerate or adversely affect it?

91673--3596--$linecast_126.gif

Raycasting is relatively expensive, so I’d say this isn’t a good method. It would also have the problem of objects potentially suddenly popping into view, since you would be linecasting to the center of the object and ignoring the bounds. (i.e., the linecast tells you nothing about whether an object should be partially visible or not.)

That would also wastefully check every object, even the ones outside the view frustum, which would be most of them. A lot of that could be cut out by using OnBecameVisible/Invisible to start and stop a coroutine instead of using Update. However, typically some kind of portal culling is used in situations like this, and this is relatively easy to script using triggers or other methods, not to mention faster than zillions of raycasts.

–Eric

More 30 second photoshop diagrams!

The diagram below is an extremely simplified layout of the environment. Below the diagram are two screen grabs that show an in-game view from these two camera locations. As you can see, at least some part of nearly any room is visible from the entryway of any other room. This isn’t a linear room-based setup, so the traditional trigger volumes might end up being too complex if even possible at all.

Due to placement of walls, most of the objects being rendered at any given time can’t actually be seen by the camera. It is these objects that I wish to remove from the render until they are within view. Any suggestions for a decent approach to this?

91764--3602--$cull_203.jpg


Ah, I see…that’s a bit of a tough question; I can’t really think of anything simple and effective at the moment.

Although one thing I’ve actually seen done is that when you’re far enough away, what would in this case be the store entrance is rendered to a flat texture and placed there. In other words you sort of have a “window” with the interior rendered on it. The actual interior is then turned off. Two problems with this are 1) Requires Pro for rendertextures (not a problem if you have Pro of course) and 2) You can usually see the transition between the rendertexture store and the actual store. I guess it depends on how important the speed-up is.

–Eric

Occlusion objects?

An occlusion object is an invisible rectangle which represents something that can’t be seen through. You basically arrange groups of these rectangles where you have walls that should obscure what is behind them (your doorways in this case).

To see if a game object is occluded, project the corners of the rectangle to get its coordinates in viewport/camera space - you can do this easily using the camera’s WorldToViewportPoint method. You also need the eight corners of each object’s bounding box, again projected into camera space. (Note that the camera space coordinate has a Z component that measures how far the point is from the camera plane.)

Basically, a game object is occluded if all its eight bounding box corners are inside a single occlusion rectangle (in camera space) and behind that rectangle (as represented by the camera space Z coordinate). You can think of this technique as a sort of “pyramid cast” that detects invisible objects rather than visible ones.

In your situation, you would probably just put a single occlusion rect across each of the V-shaped bits between doorways. Given the arrangement of objects you appear to have, you would probably improve efficiency by getting the bounding boxes of whole groups of objects (say a shelf’s worth) at once rather than testing them individually.

Not exactly straightforward, but it might be of some use to you.

Sounds like an interesting approach. So the occlusion object would be something like a plane placed within the shops that act as a mask that hides any object from the camera that completely behind the plane. Would this be a script on the camera, the plane, or the objects? I get the concept but am a little fuzzy on the execution.

To clarify confusion about the interior setup, the shelving groups and tables are whole meshes, not individual objects placed on tables. They just look unique due to UV offsets on a grid-based texture that give each of the shelf objects a different product. I wouldn’t be getting the bounding of each book and box (or casting lines from them, for that matter). That would be obscene for draw calls and asset management.

You would probably want a script on the camera or have an empty object somewhere in the scene with the script attached. You don’t necessarily need to have separate GameObjects in the scene to represent the occlusion rects. I was thinking you might make a class with four Vector3s to represent the rectangle (well, any quadrilateral, really) and put an array of this class into your occlusion management script. You would then loop through all your game objects, disabling the ones that were occluded by at least one rect/quad.

I’m still trying to wrap my head around the execution of this. I’m definitely more of an artist than a coder and I have very little experience with scripting for 3D space. Here’s some pseudo-code for what I’m thinking.

on Update()
	foreach (occlusion plane in scene)
		planeDepth = z depth of occlusion plane
		planeRect = 4 points of rectangle's corners	
		foreach(object in scene)
			objectDepth = z depth of object
			objectRect = 8 points of bounding box
			if (objDepth > planeDepth  [objectRect is within planeRect])
				object is hidden
			else
				object is shown

I can get the Z depth of the objects, but I’m not quite sure how to store and compare the bounding box points with the plane points in camera space.

To see if an object is occluded by a rect, you first need to get the corners of the rect and the corners of the object’s bounding box and use Camera.WorldToViewportPoint on each point to get their coordinates in camera space.

An easy test to see if the object is behind the rect is to find the corner of the rect that is farthest from the camera (ie, largest Z coordinate) and then check that all the object’s eight bounding box corners are farther away than that point. This isn’t very accurate, but it should work fairly well in practice.

If an object is behind the rect, then you need to check if the bounding box corners all fall inside the edges of the rect (all coordinates still in camera space). You should ignore the Z coordinate for this. One way to do this is to split the rect into two triangles and use a point-in-triangle test (unfortunately, I can’t find such a test in the Unity API, but there are some suggestions here). If all the bounding box points are inside one or other triangle, then the object is completely obscured by the rect and you need not render it.

Another approach could be to just turn the objects themselves to sprites once they have reached a certain distance. You can see this in the palm trees that come with unity. Depending on the distance it might even work for characters.

Ummm, I must be the only one since no one else is like “OMG! What game is that!?!”. So…“OMG! What game is that!?!”. Sorry for possibly newb question :slight_smile:

That game is my interactive portfolio :smile:
Unfortunately there is no gameplay yet. It’s sole function is to show of technical and artistic prowess. Feel free to explore and enjoy. http://mheiniger.com/Unity/Mall.html