How do I make the area under my water (a plane) look like its underwater?

In my game I have an area of water (The water is a plane), It looks realistic, but when I go under that plane and look up, you can’t see it. How do I make it so that not only can it be seen from the below, but also so that everything under that plane has a bluish tint? I am a beginner so sorry if this sounds basic or if it’s not even possible. (I’ve only had Unity for 6 days)

4 Answers

4

The simplest solution in your case would be to double face the water plane, so that it would be rendered even from behind: attach the script from this answer to the water plane, and it will become double faced at Start.

The second part is the underwater effect. A very reasonable (and widely used) underwater effect is to turn a bluish fog on when the camera goes below the water plane. This can be done with a script like the one below attached to the player (for First Person games):

var underwaterDens: float = 0.15;
var underwaterColor: Color = Color(0.1, 0.3, 0.4, 1.0);

private var oldFog: boolean;
private var oldDens: float;
private var oldColor: Color;
private var oldMode: FogMode;
private var curWater: Transform;
private var underwater = false;

function OnTriggerEnter(other: Collider){
	if (other.tag=="Water"){ // if entering a waterplane
		if (transform.position.y > other.transform.position.y){
			// set reference to the current waterplane
			curWater = other.transform; 
		}
	}
}

function OnTriggerExit(other: Collider){
	if (other.transform==curWater){ // if exiting the waterplane...
		if (transform.position.y > curWater.position.y){
			//  null the current waterplane reference
			curWater = null; 
		}
	}
}

function Update(){
	// if it's underwater...
	if (curWater && Camera.main.transform.position.y < curWater.position.y){
		if (!underwater){ // turn on underwater effect only once
			oldFog = RenderSettings.fog;
			oldMode = RenderSettings.fogMode;
			oldDens = RenderSettings.fogDensity;
			oldColor = RenderSettings.fogColor;
			RenderSettings.fog = true;
			RenderSettings.fogMode = FogMode.Exponential;
			RenderSettings.fogDensity = underwaterDens;
			RenderSettings.fogColor = underwaterColor;
			underwater = true;
		}
	} 
	else // but if it's not underwater...
	if (underwater){ // turn off underwater effect, if any
		RenderSettings.fog = oldFog;
		RenderSettings.fogMode = oldMode;
		RenderSettings.fogDensity = oldDens;
		RenderSettings.fogColor = oldColor;
		underwater = false;
	}
}

Remember to tag the water plane as “Water”, or nothing will happen.

and you could place a particle emitter in front of the camera to create a few bubbles to make it look a little better

–

Thank You! I'll give it a try.

–

I tried it but it didn't work. Want do think I did wrong? I took the script and attached it to the camera. When I walked through the water nothing happened.

–

I tried it but it didn't work. Want do think I did wrong? I took the script and attached it to the camera. When I walked through the water nothing happened.

–

Read the answer very carefully : This can be done with a script like the one below attached to the player

–

Underwater tutorial: Kostiantyn Dvornik :: Ideas: Unity world's coolest tutorial about water, girls and sky with FREE assets

Look here:
http://forum.unity3d.com/threads/20222-Water-plane-and-flip-texture

This goes into the details and has a sample script and video.

tldr; Make two water planes and flip one upside down…

I had to make some changes to make it work, I do not know why but the standard code posted which used a variable of type transform you blocking at the point “curWater = other.transform;”. Instead of following the correct code to those who need it. Excellent solution in any case! :slight_smile:

 var underwaterDens: float = 0.15;
 var underwaterColor: Color = Color(0.1, 0.3, 0.4, 1.0);
 
 private var oldFog: boolean;
 private var oldDens: float;
 private var oldColor: Color;
 private var oldMode: FogMode;
 private var curWater: GameObject; //CHANGED (Previous: Transform)
 private var underwater = false;
 
 function OnTriggerEnter(other: Collider){
     if (other.tag=="Water"){ // if entering a waterplane
         if (transform.position.y > other.transform.position.y){
             // set reference to the current waterplane
             curWater = other.gameObject; //CHANGED
         }
     }
 }
 
 function OnTriggerExit(other: Collider){
     if (other.gameObject==curWater){ // if exiting the waterplane...

         // CHANGED
         if (transform.position.y + 0.6 > curWater.transform.position.y) {
             //  null the current waterplane reference
             curWater = null; 
         }

     }
 }
 
 function Update(){
     // if it's underwater...

     //CHANGED
     if (curWater && Camera.main.transform.position.y < curWater.transform.position.y + 0.2){
         if (!underwater){ // turn on underwater effect only once
             oldFog = RenderSettings.fog;
             oldMode = RenderSettings.fogMode;
             oldDens = RenderSettings.fogDensity;
             oldColor = RenderSettings.fogColor;
             RenderSettings.fog = true;
             RenderSettings.fogMode = FogMode.Exponential;
             RenderSettings.fogDensity = underwaterDens;
             RenderSettings.fogColor = underwaterColor;
             underwater = true;
         }
     } 
     else // but if it's not underwater...
     if (underwater){ // turn off underwater effect, if any
         RenderSettings.fog = oldFog;
         RenderSettings.fogMode = oldMode;
         RenderSettings.fogDensity = oldDens;
         RenderSettings.fogColor = oldColor;
         underwater = false;
     }
 }

While for those who want the c # version:

public float underwaterDens = 0.15F;
public Color underwaterColor = new Color(0.1F, 0.3F, 0.4F, 1.0F);

private bool oldFog;
private float oldDens;
private Color oldColor;
private FogMode oldMode;
private GameObject curWater;
private bool underwater = false;

void OnTriggerEnter(Collider other){
    if (other.tag=="Water"){ // if entering a waterplane
        if (transform.position.y < other.transform.position.y){
            // set reference to the current waterplane
            curWater = other.gameObject;
        }
    }
}

void OnTriggerExit(Collider other){
    if (other.gameObject==curWater){ // if exiting the waterplane...
        if (transform.position.y + 0.6F > curWater.transform.position.y){
                //  null the current waterplane reference
                curWater = null; 
            }
    }
}

void Update(){
    // if it's underwater...
    if (curWater && Camera.main.transform.position.y < curWater.transform.position.y + 0.2F){
        if (!underwater){ // turn on underwater effect only once
            oldFog = RenderSettings.fog;
            oldMode = RenderSettings.fogMode;
            oldDens = RenderSettings.fogDensity;
            oldColor = RenderSettings.fogColor;
            RenderSettings.fog = true;
            RenderSettings.fogMode = FogMode.Exponential;
            RenderSettings.fogDensity = underwaterDens;
            RenderSettings.fogColor = underwaterColor;
            underwater = true;
        }

    } else // but if it's not underwater...
        if (underwater){ // turn off underwater effect, if any
            RenderSettings.fog = oldFog;
            RenderSettings.fogMode = oldMode;
            RenderSettings.fogDensity = oldDens;
            RenderSettings.fogColor = oldColor;
            underwater = false;
        }
}

I'm not sure why you needed to make any changes... I've not tried or tested this, but, when coding... var myTransform : Transform; myTransform = other.transform; myTransform.position = Vector3.zero; ... should be the same as: var myGameObject : GameObject; myGameObject = other.gameObject; myGameObject.transform = Vector3.zero; ... but practically, it's easier to use the first example where everything is a Transform, rather than a GameObject, as it doesn't require then looking up the GameObject's Transform with each operation.

–

Yes, sure! But on my version (4.6.1f1 free) transform solution not work. I also extended slightly limits (0.2, 0.6) in order to avoid some problems in graphics output phase from the surface.

–

Now I only noticed the downvote ... sure before doing so you could at least try. Certainly I do not find useful to publish stuff changed if it does not solve a real problem. :/ I also converted the code in c#, that as it was "easy" to do it, some people can definitely make use of it without having to do it by hand.

–

The main reason for the down-vote is the inefficiency of looking up a GameObject's Transform with every action, which is inefficient and definitely not recommended. I appreciate the effort put into the suggested answer, but didn't want to promote a non-recommended solution. The best solution would be getting the cached transform to work. When I'm back from holiday, I'll see if I can find the error with the accepted solution.

–