Help with an underwater fog script

I am writing a script and have gotten the fog to work but I need to make it so that the fog only enables when you are under the water plane. I am having problems with the first if statement and cannot seem to figure it out, it is very long and I am not sure it is right at all, should be a step in the right direction but it does not look right at all. the water plane is 46 by 46 so that is why I used the value of 23 to try and track the main camera when it is underneath those edges

Edit: I have completely rewritten my entire code (special thanks to bigmisterb) and need help, I cannot get the fog to activate at all, I was messing around with vectors to get the hang of them and sine there are no compiler errors I would consider that a good thing, I know there are a few I do not need at all, I was also messing around with bounds. If someone could tell me why my script is not working I would appreciate it. I was planning on editing the if statements at the bottom to a better system but that will come later when I get the system working.

Here is the new code

using UnityEngine;
using System.Collections;

public class UnderWaterEffect : MonoBehaviour {

    //the water cell that the script will use to determine when under water effects should take place.
    [Header("Water Cell")]
    public GameObject waterLevel;

    public GameObject underWaterMarker;

    //the camera that the script will control for under water effects.
    [HideInInspector]
    public Camera cameraToFollow;

    //Variables to keep track of the default fog.
    private bool defaultFog;
    private Color defaultFogColor;
    private float defaultFogDensity;


    //Variables used to determine the underwater effects color and density.
    [Header("Under Water Effect")]
    public Color shallowFogColor = Color.cyan;
    public Color deepFogColor = Color.blue;
    public float fogDensity = 0.075f;

    //Variable that determines the depth the water changes color.
    [Header("Depth Control")]
    public float waterDepth = 10.0f;

    //Defines the vectors for the water cell and the water marker.
    [HideInInspector]
    public Vector3 waterVector = new Vector3();
    [HideInInspector]
    public Vector3 cameraVector = new Vector3();
    [HideInInspector]
    public Vector3 markerVector = new Vector3();

    //Defines the bounds for the water cell.
    [HideInInspector]
    public Bounds waterBounds = new Bounds(Vector3.zero,new Vector3());

    void Start() {
        //Attaches the water plane to it's vector.
        Vector3 waterVector = waterLevel.transform.position;

        //Sets the camera to the main camera, if none can be found it attaches it to all cameras.
        cameraToFollow = Camera.main;
        if (cameraToFollow == null) cameraToFollow = Camera.allCameras[0];

        //gets the default fog values.
        defaultFog = RenderSettings.fog;
        defaultFogColor = RenderSettings.fogColor;
        defaultFogDensity = RenderSettings.fogDensity;

        //Gets the attached gameObject if nothing is assigned
        if (underWaterMarker == null) underWaterMarker = gameObject.GetComponent<GameObject>();
        Vector3 markerVector = underWaterMarker.transform.position;
        waterBounds.Encapsulate(markerVector);
    }

    void Update() {
        //Sets the cameras vector to the cameras position.
        Vector3 cameraVector = cameraToFollow.transform.position;

        //Every frame check to see if the player is under water.
        if (waterBounds.Contains(cameraVector)) {
            waterDepthFog();
        }
        else {
            RenderSettings.fog = defaultFog;
            RenderSettings.fogColor = defaultFogColor;
            RenderSettings.fogDensity = defaultFogDensity;
        }
    }

    void waterDepthFog() {
        var depthAmount = (waterBounds.max.y - cameraVector.y) / waterDepth;
        var fogColor = Color.Lerp(shallowFogColor, deepFogColor, depthAmount);

        RenderSettings.fog = true;
        RenderSettings.fogColor = fogColor;
        RenderSettings.fogDensity = fogDensity;
    }
}

ok, lets make this a bit simpler. First, I dont like running code to make things like color and density when I dont have to. So I make variables I can change when I need it. Next, since I am going to set up a test suite, I want to make this whole setting very easy… I make a method to handle it rather than a bunch of if statements.

Now, lets explore…

using UnityEngine;
using System.Collections;

public class test : MonoBehaviour {
    public Transform waterPlane;

    private bool defaultFog = false;
    private Color defaultFogColor = Color.black;
    private float defaultFogDensity = 0;

    public Color fogColor = Color.blue;
    public float density = 0.075f;

	// Use this for initialization
	void Start () {
        defaultFog = RenderSettings.fog;
        defaultFogColor = RenderSettings.fogColor;
        defaultFogDensity = RenderSettings.fogDensity;
	}
	
	// Update is called once per frame
	void Update () {
        if (waterPlane == null) return;

        // test the y position to see if it is under the plane
        SetFog(transform.position.y < waterPlane.position.y);

        // test fog according to the bounding box of the water "box")
        SetFog(waterPlane.gameObject.GetComponent<Renderer>().bounds.Contains(transform.position));

        // using a plane that can be rotated
        SetFog(waterPlane.InverseTransformPoint(transform.position).y < 0);
	}

    void SetFog(bool underwater) {
        RenderSettings.fog = underwater ? true : defaultFog;
        RenderSettings.fogColor = underwater ? fogColor : defaultFogColor;
        RenderSettings.fogDensity = underwater ? density : defaultFogDensity;
    }

}

I basically set the plane up 3 ways, either its under something, in something, or below a plane which could be rotated.

I see what you did and can tell right away you are a lot better at this than I am, but it will only detect the y coordinates, I need it to detect every coordinate since this is going to be a large open world with several different water heights. Don’t I need some way of detecting when I am underneath that water cell?

I was going to use collision boxes but that system was even buggier it seemed so I just attached this script to my water plane and went from there.

Sorry I am a complete amateur, I thank you for your script though it gives me some ideas I can mess around with and some things to test out, but right now I can just not get my water working right.

OK, so lets look at it as the script being attached to a cube and looks for the camera.

using UnityEngine;
using System.Collections;

public class test : MonoBehaviour {
    public Camera camera;
    public Renderer renderer;

    private bool defaultFog = false;
    private Color defaultFogColor = Color.black;
    private float defaultFogDensity = 0;

    public Color topFogColor = Color.red;
    public Color bottomFogColor = Color.blue;
    public float fogDensity = 0.075f;
    public float maxColorDepth = 10;

	// Use this for initialization
	void Start () {
        camera = Camera.main;
        if (camera == null) camera = Camera.allCameras[0];
        defaultFog = RenderSettings.fog;
        defaultFogColor = RenderSettings.fogColor;
        defaultFogDensity = RenderSettings.fogDensity;
        renderer = gameObject.GetComponent<Renderer>();
	}
	
	// Update is called once per frame
	void Update () {
        if (camera == null || renderer == null) return;

        // test fog according to the bounding box of the water "box")
        SetFog(renderer.bounds.Contains(camera.transform.position));
	}

    void SetFog(bool underWater)
    {
        if (!underWater) {
            RenderSettings.fog = defaultFog;
            RenderSettings.fogColor = defaultFogColor;
            RenderSettings.fogDensity = defaultFogDensity;
            return;
        }

        var depthAmount = (renderer.bounds.max.y - camera.transform.position.y) / maxColorDepth;

        var fogColor = Color.Lerp(topFogColor, bottomFogColor, depthAmount);

        RenderSettings.fog = true;
        RenderSettings.fogColor = fogColor;
        RenderSettings.fogDensity = fogDensity;
    }
}

I even put something in there to control color for depth, you could also control density as well.

I am attempting to get it working, I am not sure what I am doing wrong but I do not see anything wrong with your code other than the variables camera and renderer it would not let me use, so I am sure it is my fault. Thank you for this code I will get it working and see what modifications can be made for my game.

use the code the way it is. put it on a box, then move the camera into that box from the Scene pane. when it goes into the box, the fog will happen.

It still did not work, is it because I set my box to be a trigger? or is it because of my complicated nested camera system for my sky? I am not really sure what I am doing wrong at this point.

Edit: I appreciate the code, and I do not want to sound ungrateful, but what was wrong with my code? how could I make mine work? I am just curious, to see what I was doing wrong or if that was horribly inefficient.

Bump

could someone look at the edit in the first post and help me please, I rewrote my script and need some advise. I could not get bigmisterb’s code working either and since this is my first game and I need to learn this stuff I did not want to use his script I wanted to make my own, I did use alot of his concepts though.

the code I did doesn’t use triggers, or physics at all, it looks at the position of the camera, and sees if it is within the bounds of the box that is your water. If it is, then it uses the depth of that camera to determine what color the fog is.

Make a big box in your scene, and put this script on it, (say 100 x 50 x 100)
Position the camera above that box.

Press Play and swap to the Scene pane (from the Game pane)

Use the move tool to move the camera down into the large box.

I understand that and I have used it exactly as you have said, I could not get it working no matter what I tried, like I said I am not sure what I was doing wrong but I could not get the script to activate the fog, I placed a box put this script on it, replaced test at the top to the name of my script exactly, I double checked that, assigned the camera and the renderer, but it just would not activate the fog.

Edit: is it because the box is declared as a renderer and I am not actually rendering it? I turned mesh renderer off and was testing it directly under my water plane.

so, what you are looking for is a bounding box below a plane…

lets paraphrase it…

I have a plane, that plane has a renderer, that renderer has bounds, those bounds (in theory) should be 0 in height.

So get the bounds from that renderer, set the bound min.y to - infinity. Now, test against those bounds as to where the camera is.

In otherwords, you dont need a box, just a plane, where the plane looks to see if the camera is under it anywhere.

To get the depth, you then subtract the camera’s y from the bounds max.y. (of course, if this number is negative, then you are above the plane)

No I think you misunderstood, having it be controlled by a box is great I can have caves and such under the water, ect. I only had the plane there for looks, it was not attached in any way other than the box is a child of it so I can have it set as a prefab easier… I was wondering if the problem could be because you have the box declared as a renderer, not a gameobject, I have the renderer turned off so you cannot see he box at all, I was wondering if that could be my problem. I have never messed with renderers before.

it could be, but shouldnt be. This doenst work for caves and such though. You would have to create a area system for that.

Say, you have the same type of thing that I did for the area, but they are nothing but lists of bounding boxes with some other info about the area. You place them in order of importance, so if you have an area that is a cave, that is before the area that is a sea. When you are in the cave, that area is marked to not have fog, or has fog based off of what that area should be. the sea, has a different area.

So to get the area you are in, you go through all the entries and find the first bounding box that you are in. That box, is then what you display.

I do not get that, shouldn’t the fog only appear when inside the box with your script? so with caves as long as the box is above the cave wouldn’t it be fine? but I will cross that bridge when I get there for now I need to mess around with some things and figure out why the fog is not appearing at all. Have you used that script before? is it possible that you overlooked something? or is this something I am doing? I have tried everything I could think of, the only thing I have not tested is if it has something to do with my camera system for the sky, but that should not be affecting this.

Edit: I have found out the problem with your script, it only works on one prefab instance, I need it to work with severeral hundred, any water prefabs placed after the first are ignored.

imagine you are under water, and you come upon a cave that is underwater, that cave has air, you can get in and move around, this means that you are no longer in water. So in order to handle that, you will need to have an air pocket, that air pocket has to be defined somehow.

Edit…

you apply that script to as many blocks as you want. the problem only happens when you want to do underwater things like air pockets, then it becomes complicated.

Ah, that makes sense, I was thinking about like caves under a lake itself, where the entrance is somewhere above ground.

How can I fix it so that your script works on all prefabs not just the first one to be placed onto the scene? I need it to be able to attach to a block, have a water plane positioned at the exact top of the block, make the block a child of the water plane, then prefab the whole thing and be able to just drag the prefab onto the scene and not have to connect anything to the script after it is made a prefab. Right now it is only activating the fog correctly for one prefab and not the rest.

Edit: it would also be nice if in the editor the fog could turn on also, rather than just in the game.

the script is already designed for that. you can attach it to as many blocks as you want. Any time the main camera goes into that block, it starts the process of underwater fog.

Given a scenario of a cave that could go under a block of water, and the previous explanation, you would simply give that whole cave a indicator that says that you have no fog. Similar to an underwater cave. The only deal would be that you have to make sure that the bounds of the cave never go into the water above it. You could also put multiple non fog blocks together to get shapes to help. but I dont think this is the direction you are going.

Okay, sorry for the confusion then, I got it working finally but it only activates one block at a time, and ignores the rest. could this be an engine bug? I am getting tired of this at this point, I have no idea why it is not working for me and I am getting frustrated. I will test your script a lot more though and see what I can come up with.

Is there a way you could make it also effect the editor? or is it not worth it? Also what about underneath the water, is there a way to make underneath transparent? I am just using the default water.

Edit: could this be some sort of engine bug? I cannot think of anything else at this point, the fog only activates when within one cell. I tried closing unity and jumping into a different cell thinking that only the first cell entered would activate the fog but it is always the same cell, so it must be getting caught in the ram or something, I am not sure. Other than your script being insanely complicated compared to my other beginner scripts I see nothing wrong with it, and I have followed your exact instructions.

This is getting very frustrating, this should be easy and I do not see anything wrong with the code and it simply refuses to work right, should I make a custom box so I do not need to scale it? should I rethink my camera system? should I rethink my water system? It just refuses to work and there is nothing I am doing wrong I can usually think of a solution that works or that will give me more to work with but with this issue the script simply refuses to work correctly, I have no idea where to go from here.