Over the past several months working on the Dungeon theme for Labyrintheer, I’ve changed my camera angle several times. I keep moving it higher to prevent walls and such from occluding the player, but I’m never happy with such an oblique view. So, over the past few days I’ve been looking at options to make walls transparent when they are between the player and the camera.
Some solutions simply disable the geometry. This isn’t acceptable for my game, and I suspect for many. You could accidentally walk backwards out of the playable area, or an errant AI could take a bad turn during it’s pathing and fall off the world. Plus, disabling geometry just doesn’t seem like an elegant solution. My primary goal (and I’m still working on it) is to use a shader for this directly, though that seems like it has some major pitfalls (how do you tell a shader about an object other than the one that it’s drawing?).
So, for now I’m cheating with a very small amount of code and an extra material for objects that I want to hide.
Basically, I’ve duplicated the four wall materials I have, and the duplicate materials use transparency with an alpha value of 100.
My player controller script now calculates it’s distance from the camera every frame (though I think this might be able to be done once in Awake() since the distance should be fairly static), like this:
void Update ()
{
GetInput();
ProcessInput();
distanceSquared = (transform.position - Camera.main.transform.position).sqrMagnitude;
}
public float Dist()
{
return distanceSquared;
}
Then created a script to go on the walls (or any object that needs to be transparent to prevent occlusion), as such:
TransMaterialSwap.cs
using UnityEngine;
public class TransMaterialSwap : MonoBehaviour {
public Material _original;
public Material _transparent;
private GameObject player;
private playerController pC;
private Renderer rend;
void Start()
{
player = GameObject.FindWithTag("Player");
pC = player.GetComponent<playerController>();
rend = this.GetComponent<Renderer>();
}
void Update()
{
if ((transform.position - Camera.main.transform.position).sqrMagnitude < pC.Dist())
{
rend.material = _transparent;
}
else
{
rend.material = _original;
}
}
}
In the inspector I set both the original material and the transparent material. If the object is between the camera and the player, it switches the object’s material to the transparent material. It looks like this:
There are a few issues here. First, I still need to profile this to see if the solution gives my runtime performance a hit. I don’t suspect it’ll be TOO bad, but it doesn’t hurt to check, especially with larger maps. I may look into options to only run the check if the object is visible to the camera rather than always checking on Update(), every frame for every wall. The other issue is that by making it transparent, light comes through. I’m not sure how big an issue this will be – it’ll require some play testing. But it may be an issue in some situations.
Lastly, as I said, I really do want to attempt this in a shader. I figure it’s a good method to learn shader programming, even if exactly what I want isn’t possible.
Already started making changes. Using BoxCastAll from the camera to the player is far more performant than having every wall section check its relative position every frame during Update(). I’m sure I can get more performance than this still, though. Hmmm…