3
\$\begingroup\$

Let's say I want to replicate Planeshifting from Legacy of Kain: Soul Reaver in Unity.

There are 2 realms: Spectral realm and Material realm.

The Spectral realm is based on the Material realm, only has the geometry distorted and certain objects fade out/become non-interactive.

In Soul Reaver, it is used as means to go to areas where you normally wouldn't be able to in Material (distorting geometry), to use other powers (such as going through grates).

My question is: Is it even possible at all to implement this in Unity 3D? (I would need the Scene(level) or the objects to have 2 states somehow that I could switch beetween/distort to real-time.)

\$\endgroup\$
3
\$\begingroup\$

Absolutely, there are several approaches you could use.

  • You could use one scene for each. This would involve some duplication of work potentially, but you could build each scene from prefabs to minimize that.

    This will cause there to be some load time when you switch from one realm to another, though you may be able to eliminate that with LoadSceneAsync().

  • You could tag all objects from each realm with a tag for that realm, and use GameObject.SetActive(bool active) to flip all the objects from one realm off and the objects from another realm back on.

    Again this would mean two versions of everything would have to be built, but depending on how warped they are that might be the easiest way to do it. This would make flipping between realms relatively instant.

  • Progamatically distort the objects in the scene when you switch between realms. This may be the best approach if the degree of distortion is not extreme.

    Tag each gameobject that will need to be modified, use FindGameObjectsWithTag(string tagname) to get a list of all those objects, iterate over them and make the necessary changes. You can easily swap shaders/textures or even meshes on each game object as you flip between one mode and another.

    This may introduce a slight pause in the gameplay depending on how much manipulation has to be done to each game object. You could easily disguise that with some sort of transition effect.

\$\endgroup\$
2
\$\begingroup\$

This is kind of an extension to @jackmott's answer, similar his suggestions, but different.

Instead of using GameObject.SetActive() to flip the states of everything in the scene, I would instead suggest using shaders, material flags, and your own method that flags objects as being visible or invisible depending on the current render state. (This is also slightly related to point 3, doing it programatically, as well).

The benefits are that you only need to create your scene once, and objects that are only visible in one "realm" are cleverly not-rendered when the player isn't in that realm.

Take a look at Camera#SetReplacementShader(). In forcing the main camera to use a different shader to render every object in the scene, you can change between the material realm (objects use their own shaders) and the spectral realm (objects are rendered using a custom SpectralShader that you will need to create) which will do the color shifting, blurring, and vertex distortion.

Can't find my screenshot at the moment (on the wrong computer), but I've got something similar set up for my own project right now. It lets me draw outlines of enemies through walls (if the player has that ability active), not draw enemies that are invisible (but they will get outlines!), or draw them as unlit blobs (visible through walls). I use the last one for things like notification icons, e.g. a red ! that hovers over an objective point.

Which state is active depends on which camera is currently rendering, what attribute flags it has, and the enemy being rendered. I had to do a little hacking to get this to work, but I have an event notification system that fires off an event during OnPreRender (this only happens on the object the Camera is attached to, not for every object being rendered!) to notify every object about to be rendered the detail specifics of the render being performed (can the player see through walls, is the camera a remove-viewing device, and so on). Objects that should be invisible turn their renderer off, objects that should turn it back on, and a couple other flags get flipped via Material#SetOverrideTag.

Shader pass tags are super important when dealing with SetOverrideShader: When the replaced shader runs, it looks at the original shader's tags. If the replaced shader has the same tag with the same value, the pass runs. See Rendering with Replaced Shaders.

This will be a very hard avenue to pursue, but it will also be the one that will have the best looking result with the most flexibility and least amount of effort spent in level creation. And almost certainly the method employed by Legacy of Kain. The hardest part will be creating the custom shader. My own, for my three or four simple effects, is hundreds of lines long (the outline pass alone is 165!)

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.