Fountain – Imagism Environment Process

The Plan

For this project, I wanted to create a 3D environment that digitalises an Imagism poem I wrote:

Leaves fall over stone
Where water never changes
But always moves

This was adapted from a previous poem I wrote while practising Haiku:

Dead leaves on cobblestone
Cold water, flowing sound
Watch and wait

I also wanted to use this project to experiment with textures and models from SketchFab and other places, as I currently have little experience with 3D design.

 

The Process

I began by building out the scene in grey box. I decided the priorities would be the fountain, ground, leaves, and the camera. I experimented with a player controller but ultimately decided it wasn’t the kind of project I wanted the viewer to move around in. I just wanted it to be something to look at, which was a small reference to the first version of my poem from the last line: “watch and wait”.

I built the fountain and walls using basic cubes in Unity, and I created the water using planes with a transparent blue material attached. I sourced each texture for the walls, ground, and fountain stone online from a website called Poliigon. The cobblestone texture was exactly what I imagined for my scene.

I found a model of various autumn leaves on SketchFab and scattered them randomly throughout the scene, mostly focused inside the camera view, as well as high above to create shadows of falling leaves.

I encountered two problems working with these models. Firstly, the leaf texture image left a slightly grey transparent box around the leaf cut out. Secondly, rotating the leaves slightly skewed them rather than turning them like any other object. Despite these issues, I decided to use them as they included variations in shape and colour, and I thought the style matched the other textures used in my scene.

Finally, to complete this first pass of the environment, I added two trees I sourced from SketchFab and placed them behind the camera to create shadows over the fountain and the wall. I also found a sound only of water running which helped add life into the scene. The project is not final at this point as I want the player to be able to move the camera in some way, and I want to add movement into the scene with small animations.

Fountain first version.

 

Several weeks later…

It has been almost two months since I last worked on the Imagism environment. During this time, I worked on three more projects in the Minimalist Interactives series and gained more knowledge and skill in Unity. I also have a better perspective of what I enjoy doing and where I want to focus my future work. I wanted this to be the last work I revisited before finalising the series to demonstrate how my practice has evolved throughout.

The first major change I made to the environment was removing all textures from the models and replacing them with solid colours. I enjoy the challenge of trying to express meaning using visual constraints like this, and it has become clear to me that a simplified and minimal look is a large part of my design style.

I removed the SketchFab leaves completely and modelled a basic leaf in Maya to use in the environment instead. I then created a script to spawn a leaf every second above the environment using same method I learnt while working on Seasons. Each leaf has a random size, rotation, colour and drag. Now there’s movement in the scene while still having lots of variation in the leaves.

public class LeafSpawner : MonoBehaviour
{
    [Header("Spawn Properties")]
    public GameObject objectToSpawn;
    public float spawnTime;

    [Header("Object Scale")]
    public float sizeMin;
    public float sizeMax;
    public bool isAsymmetrical;

    [Header("Object Position")]
    public float positionMin;
    public float positionMax;

    void Start()
    {
        StartCoroutine(SpawnObject());
    }

    public IEnumerator SpawnObject()
    {
        while (true)
        {
            // Spawn object in a random (x and z) position above the sceen (y = 30) with a random rotation (x, y, z)
            GameObject spawnedObject;
            Vector3 randomRotation = new(Random.Range(1, 360), Random.Range(1, 360), Random.Range(1, 360));
            spawnedObject = Instantiate(objectToSpawn, new Vector3(Random.Range(positionMin, positionMax), 20, Random.Range(positionMin, positionMax)), Quaternion.Euler(randomRotation));

            // Set the object scale to a random size
            float randomScaleOne = Random.Range(sizeMin, sizeMax);
            float randomScaleTwo = Random.Range(sizeMin, sizeMax);
            if (isAsymmetrical)
                spawnedObject.transform.localScale = new Vector3(randomScaleOne, randomScaleTwo, randomScaleOne);
            else
                spawnedObject.transform.localScale = new Vector3(randomScaleOne, randomScaleOne, randomScaleOne);

            yield return new WaitForSeconds(spawnTime);
        }
    }
}
LeafSpawner script. Unity/C#.
public class LeafRandomiser : MonoBehaviour
{
    Rigidbody rb;

    [Header("Physics Settings")]
    public float dragMin;
    public float dragMax;

    [Header("Color Settings")]
    Renderer rend;
    public bool canChangeColor;
    public Color[] objectColors;

    void Start()
    {
        rb = gameObject.GetComponent<Rigidbody>();
        rend = gameObject.GetComponent<Renderer>();

        float dragAmount = Random.Range(dragMin, dragMax);
        rb.drag = dragAmount;

        if (canChangeColor)
        {
            rend.material.color = objectColors[Random.Range(0, objectColors.Length)];
        }
    }
}
LeafRandomiser script. Unity/C#.

I also replaced the SketchFab tree with one from the Unity Asset Store. This model comes with a shader that animates the foliage and simulates wind in the environment.

Next, I positioned four cameras around the environment and coded a script to switch the camera when the left mouse button is clicked. I attempted to make each angle unique and interesting while ensuring the models of the trees were not in view.

public class SwitchCamera : MonoBehaviour
{
    public GameObject[] cams;
    int currentCam = 0;

    void Start()
    {
        // set all cameras to inactive
        foreach (GameObject o in cams)
        {
            o.SetActive(false);
        }

        // set first camera to active
        cams[currentCam].SetActive(true);

    }

    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            // set current camera inactive
            cams[currentCam].SetActive(false);

            currentCam++;

            // reset counter to beginning if the number reaches more than cameras available
            if (currentCam >= cams.Length)
            {
                currentCam = 0;
            }

            cams[currentCam].SetActive(true);
        }
    }
}
SwitchCamera script. Unity/C#.

Although I was happy with the transformation of the environment after these changes, I still felt like it was lacking. The only aspect I hadn’t changed was the background, which was just a flat colour that didn’t add any value to the scene. I searched on the Unity Asset Store and found a skybox pack with vibrant but simple styles. This instantly made the environment feel more alive. While I was switching day, night and sunset skyboxes to find the right colour combination with my existing materials, I thought why not allow the player to change the skybox themselves.

Applying the same logic as the camera script, I added the ability to change the time of day with the right mouse button to cycle through three skyboxes, and three rotations for the Directional Light which change how far the shadows of the trees extend over the area.

public class SwitchSkybox : MonoBehaviour
{
    public Material[] skyboxes;
    public Light directionalLight;
    public Vector3[] lightDirections;
    public AudioSource[] audioSources;

    int currentSkybox = 0;

    void Start()
    {
        // mute all audio sources
        foreach (AudioSource aS in audioSources)
        {
            aS.mute = true;
        }

        // unmute first audio source
        audioSources[0].mute = false;

        // set first skybox and light direction
        RenderSettings.skybox = skyboxes[0];
        DynamicGI.UpdateEnvironment();
        directionalLight.transform.localRotation = Quaternion.Euler(lightDirections[0]);
    }

    void Update()
    {
        if (Input.GetMouseButtonDown(1))
        {
            // mute current audio source
            audioSources[currentSkybox].mute = true;

            currentSkybox++;

            // reset counter to beginning if the number reaches more than skyboxes available
            if (currentSkybox >= skyboxes.Length)
            {
                currentSkybox = 0;
            }

            // set skybox, light direction and audio source
            RenderSettings.skybox = skyboxes[currentSkybox];
            DynamicGI.UpdateEnvironment();
            directionalLight.transform.localRotation = Quaternion.Euler(lightDirections[currentSkybox]);
            audioSources[currentSkybox].mute = false;
        }
    }
}
SwitchSkybox script. Unity/C#.

Each time of day also has different audio playing. For example, you can hear bird sounds during the day and crickets at night. The water sound is always playing in the background; however, I changed it to use a 3D sound space instead of 2D and placed it in the middle of the fountain so that it sounds louder the closer the camera is to it.

Fountain final version.

 

The Outcome

Out of all the projects in the minimalist series, Fountain has been the most experimental, both technically and personally. It extended further than its concept of Imagism and digitalising poetry, and challenged my confidence. I tried something new but failed in the execution. However, I believe every failure is a necessary step towards growth. Fountain ultimately led the way to discovering what I like and don’t like and reaffirmed my design style.

 

Go To Project