︎︎︎New World



Tags :
︎ 360 VR Experience

Status :
︎ Published at MOR

Role :
Developer , Tilt-Brush 


︎ Collaboration with Kerenza Harris


︎ VRHAM! Festival

︎Hamburg, Germany
︎ 2020 06

︎ Project Breakdown


. “New World” is a 360 Virtual Reality movie that has been created as a response to the COVID-19 isolation and social distancing

. the story narrates isolation through an artistic key featuring the story of Astra and Yu

. Astra is a young girl, YU is Astra’s guide. The dialougues between the two character is lived in first person in the shoes of Astra 
︎


. 360 Cinematic video

 
︎ VR Tilt-Brush


.  some of the project assets made with Tilt-Brush. 

︎  Code Sample : Procedural Ocean


. some variations of waves are instantiated as a grid and moved through a script that simulates a perpetual ocean behaviour

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
using UnityEngine;
using System.Collections;

public class Ocean : MonoBehaviour
{
    // axis enum 
    public enum Axis { X, Y, Z };
    [Header("Animation Parameters")]
    [Tooltip("Axis the deformer to work on")]
    public Axis axis = Axis.Y;
    [Tooltip("Axis the curve will act on")]
    public Axis curveInfluence = Axis.X;
    [Tooltip("Animation Deformation")]
    public AnimationCurve animationCurve;
    [Tooltip("Waves frequency")]
    public float frequency = 0.5f;
    [Tooltip("A way to keep tracking the cycle throught the waves")]
    public float cycle = 1.0f;
    [Tooltip("Waves Height")]
    public float waveHeight = 1.0f;
    [Tooltip("the speed of the waves animation")]
    public float animationSpeed = 10.0f;
    [Tooltip("move through the corresponding axis")]
    public float moveX, moveY, moveZ = 0;
    [Tooltip("Animate the waves")]
    public bool animate = false;
    // private variables
    // array of transform for all the object subjected to the behavior
    Transform[] originalObjects;
    // array of transform for all the object moving
    Transform[] movedObjects;
    // array of the original positions 
    Vector3[] originalObjectsPos;
    // array of the position that changed 
    Vector3[] movedObjectsPos;
    // 
    float normalized;
    float curveValue;
    // setting boundaries for the curve 
    float yMin, yMax, xMin, xMax, zMin, zMax = 0;
    float offsetMin, offsetMax = 0;
    // a new object position 
    Vector3 newObjectPos;
    // array defining the original pos coordinates 
    private float[] OriginalY, OriginalX, OriginalZ;


    void Start()
    {
        // https://docs.unity3d.com/Manual/animeditor-AnimationCurves.html
        // Animation Clip controls how that property changes over time.
        if (animationCurve.length == 0)
        {
            animationCurve = new AnimationCurve(new Keyframe(0, 1), new Keyframe(1, 1));
        }
        // create an array of objects - children of a parent 
        originalObjects = new Transform[transform.childCount];
        // recreated a second array with the previous objects 
        movedObjects = new Transform[originalObjects.Length];
        // respectively created a third array 
        movedObjectsPos = new Vector3[originalObjects.Length];
        // these are the orginal coordinates of the objects 
        OriginalY = new float[originalObjects.Length];
        OriginalX = new float[originalObjects.Length];
        OriginalZ = new float[originalObjects.Length];
        // we created a position array with all the previous coordinates arrays 
        originalObjectsPos = new Vector3[originalObjects.Length];
        // for loop taking in consideration the children list 
        for (int i = 0; i < transform.childCount; i++)
        {
            // assigning values 
            // original objects are all the children transform 
            originalObjects[i] = transform.GetChild(i);
            // moved objects are all the children positions 
            movedObjectsPos[i] = originalObjects[i].position;
            // all of the children positions are the original objects positions 
            originalObjectsPos[i] = originalObjects[i].position;
        }
        // at this stage moved objects are the original objects 
        movedObjects = originalObjects;
        // if the array is not - not exsisting 
        if (originalObjects.Length != 0)
        {
            // fill the following variables 
            // at this stage min=max
            // considering the very first element of the list 
            // as a reference 
            yMin = originalObjects[0].position.y;
            yMax = originalObjects[0].position.y;
            //
            xMin = originalObjects[0].position.x;
            xMax = originalObjects[0].position.x;
            //
            zMin = originalObjects[0].position.z;
            zMax = originalObjects[0].position.z;
        }
        // for loop going through the original objects transform 
        for (int i = 0; i < originalObjects.Length; i++)
        {
            // re assigning the original value 
            OriginalY[i] = originalObjects[i].transform.position.y;
            OriginalX[i] = originalObjects[i].transform.position.x;
            OriginalZ[i] = originalObjects[i].transform.position.z;
            // checking and comparing the values of all the list
            // with the element took into consideration as first 
            // and build the behavior up from there 
            // yMin
            if (originalObjects[i].position.y < yMin)
            {
                yMin = originalObjects[i].position.y;
            }
            // yMax 
            if (originalObjects[i].position.y > yMax)
            {
                yMax = originalObjects[i].position.y;
            }
            // xMin
            if (originalObjects[i].position.x < xMin)
            {
                xMin = originalObjects[i].position.x;
            }
            // xMax
            if (originalObjects[i].position.x > xMax)
            {
                xMax = originalObjects[i].position.x;
            }
            // zMin
            if (originalObjects[i].position.z < zMin)
            {
                zMin = originalObjects[i].position.z;
            }
            // zMax
            if (originalObjects[i].position.z > zMax)
            {
                zMax = originalObjects[i].position.z;
            }
        }
    }
    // considered a fixed update for the steady flow 
    void FixedUpdate()
    {
        TransformSineWave();
        if (animate)
        {
            tickingCycle();
        }
    }
    // 
    public void tickingCycle()
    {
        cycle += Time.deltaTime * animationSpeed;
        // the cycle keeps ticking based on time and speed multiplier 
    }
    void TransformSineWave()
    {
        // based on the values corrisponding on the curve we have 
        // a number of possibilies 
        switch (curveInfluence)
        {
            // the min and max change based on the 
            // enum axis we picked 
            case Axis.X:
                offsetMin = xMin;
                offsetMax = xMax;
                break;

            case Axis.Y:
                offsetMin = yMin;
                offsetMax = yMax;
                break;

            case Axis.Z:
                offsetMin = zMin;
                offsetMax = zMax;
                break;
        }
        // this goes to trigger a condition based of
        // the staring point we set up previously 
        // normalizing a space from 0 to 1
        if (offsetMin == offsetMax)
        {
            offsetMin = 0;
            offsetMax = 1;
        }
        // for all theobjects 
        for (int i = 0; i < originalObjects.Length; i++)
        {
            // this float is the addiction to the position 
            float x, y, z;
            x = originalObjectsPos[i].x + moveX;
            y = originalObjectsPos[i].y + moveY;
            z = originalObjectsPos[i].z + moveZ;
            // locally defined a new variable 
            float new_x = x;
            float new_y = y;
            float new_z = z;
            // based on the axis we chose here is the process of 
            // normalizing the values defining the ratio 
            // for normalizing continuosuly the value 
            // using normalization formula 
            // https://www.wallstreetmojo.com/normalization-formula/
            switch (axis)
            {
                case Axis.X:
                    switch (curveInfluence)
                    {
                        case Axis.X:
                            normalized = (x - offsetMin) / (offsetMax - offsetMin);
                            break;

                        case Axis.Y:
                            normalized = (y - offsetMin) / (offsetMax - offsetMin);
                            break;

                        case Axis.Z:
                            normalized = (z - offsetMin) / (offsetMax - offsetMin);
                            break;
                    }
                    // evaluate 
                    // https://docs.unity3d.com/ScriptReference/AnimationCurve.Evaluate.html
                    // returns float The value of the curve, at the point in time specified.
                    // normalized = The time within the curve you want to evaluate (the horizontal axis in the curve graph).
                    curveValue = animationCurve.Evaluate(normalized);
                    // sinWave formula 
                    // https://answers.unity.com/questions/434717/how-to-make-a-sine-wave-with-a-transform.html
                    // full explanation of the math formula - mecanim could resolve codeless but why not
                    new_x = x + Mathf.Sin(frequency * z + cycle) * waveHeight * curveValue;
                    // wave height multiplies the effect 
                    // z is the opposite parameter on the other axis 
                    // the cicle keeps ticking 
                    // the curve value provide the point of the cycle
                    // is the animation speed is lower the cycle is slower 
                    break;

                case Axis.Y:
                    switch (curveInfluence)
                    {
                        case Axis.X:
                            normalized = (x - offsetMin) / (offsetMax - offsetMin);
                            break;

                        case Axis.Y:
                            normalized = (y - offsetMin) / (offsetMax - offsetMin);
                            break;

                        case Axis.Z:
                            normalized = (z - offsetMin) / (offsetMax - offsetMin);
                            break;
                    }
                    curveValue = animationCurve.Evaluate(normalized);
                    new_y = y + Mathf.Sin(frequency * x + cycle) * waveHeight * curveValue;
                    break;

                case Axis.Z:
                    switch (curveInfluence)
                    {
                        case Axis.X:
                            normalized = (x - offsetMin) / (offsetMax - offsetMin);
                            break;

                        case Axis.Y:
                            normalized = (y - offsetMin) / (offsetMax - offsetMin);
                            break;

                        case Axis.Z:
                            normalized = (z - offsetMin) / (offsetMax - offsetMin);
                            break;
                    }
                    curveValue = animationCurve.Evaluate(normalized);
                    new_z = z + Mathf.Sin(frequency * x + cycle) * waveHeight * curveValue;
                    break;
            }

            // the new values initially defined provide the new current position on frame 
            newObjectPos = new Vector3(new_x, new_y, new_z);
            // we move the object 
            movedObjectsPos[i] = newObjectPos;
        }
        // finally we applied the new defined position of the moved object pos in the transform 
        // transpform.position = vector3 
        for (int x = 0; x < originalObjects.Length; x++)
        {
            movedObjects[x].position = movedObjectsPos[x];
        }
    }
}