public override void Load()
        {
            if (Fetched)
            {
                return;
            }

            var images = DoFetchImages(FileNames);

            _fft        = Fourier.FFT2(Images[0], false);
            ViewColumns = 9;
            ViewRows    = 9;
            Images      = images;
            Rearrange(0, 0, 300, 150, 9);
        }
示例#2
0
        private void DoApply(UnmanagedImage image, UnmanagedImage output)
        {
            var fimg = Fourier.FFT2(image);

            if (Width != fimg.Width ||
                Height != fimg.Height)
            {
                throw new DimensionMismatchException();
            }

            fimg.C0.MultiplyWith(C0);
            fimg.C1.MultiplyWith(C1);
            fimg.C2.MultiplyWith(C2);
            output.Draw(fimg.InverseFFT2(false));
        }
示例#3
0
    void GenerateBumpmaps()
    {
        if (!normalDone)
        {
            for (int idx = 0; idx < 2; idx++)
            {
                for (int y = 0; y < n_height; y++)
                {
                    for (int x = 0; x < n_width; x++)
                    {
                        float   yc    = y < n_height / 2 ? y : -n_height + y;
                        float   xc    = x < n_width / 2 ? x : -n_width + x;
                        Vector2 vec_k = new Vector2(2.0f * Mathf.PI * xc / (size.x / normal_scale), 2.0f * Mathf.PI * yc / (size.z / normal_scale));

                        float    iwkt   = idx == 0 ? 0.0f : Mathf.PI / 2;
                        ComplexF coeffA = new ComplexF(Mathf.Cos(iwkt), Mathf.Sin(iwkt));
                        ComplexF coeffB = coeffA.GetConjugate();

                        int ny = y > 0 ? n_height - y : 0;
                        int nx = x > 0 ? n_width - x : 0;

                        n_x[n_width * y + x] = (n0[n_width * y + x] * coeffA + n0[n_width * ny + nx].GetConjugate() * coeffB) * new ComplexF(0.0f, -vec_k.x);
                        n_y[n_width * y + x] = (n0[n_width * y + x] * coeffA + n0[n_width * ny + nx].GetConjugate() * coeffB) * new ComplexF(0.0f, -vec_k.y);
                    }
                }
                Fourier.FFT2(n_x, n_width, n_height, FourierDirection.Backward);
                Fourier.FFT2(n_y, n_width, n_height, FourierDirection.Backward);

                for (int i = 0; i < n_width * n_height; i++)
                {
                    Vector3 bump = new Vector3(n_x[i].Re * Mathf.Abs(n_x[i].Re), n_y[i].Re * Mathf.Abs(n_y[i].Re), n_width * n_height / scale / normal_scale * normalStrength).normalized * 0.5f;
                    pixelData[i] = new Color(bump.x + 0.5f, bump.y + 0.5f, bump.z + 0.8f);
                    //			pixelData[i] = Color (0.5, 0.5, 1.0);
                }
                if (idx == 0)
                {
                    textureA.SetPixels(pixelData, 0);
                    textureA.Apply();
                }
                else
                {
                    textureB.SetPixels(pixelData, 0);
                    textureB.Apply();
                }
            }
            normalDone = true;
        }
    }
示例#4
0
        private void miBackwardFFT_Click(object sender, System.EventArgs e)
        {
            if (this.ActiveCImage == null)
            {
                return;
            }

            CImage cimage = this.ActiveCImage;
            float  scale  = 1f / (float)Math.Sqrt(cimage.Width * cimage.Height);

            ComplexF[] data = cimage.Data;

            Fourier.FFT2(data, cimage.Width, cimage.Height, FourierDirection.Backward);

            int offset = 0;

            for (int y = 0; y < cimage.Height; y++)
            {
                for (int x = 0; x < cimage.Width; x++)
                {
                    if (((x + y) & 0x1) != 0)
                    {
                        data[offset] *= -1;
                    }
                    offset++;
                }
            }

            cimage.FrequencySpace = false;

            for (int i = 0; i < data.Length; i++)
            {
                data[i] *= scale;
            }

            this.ActiveCImage = cimage;
        }
示例#5
0
    void Update()
    {
        //If player null, search for player by Player tag
        if (player == null)
        {
            player = GameObject.FindGameObjectWithTag("Player").GetComponent <Transform>();
        }

        //Get sun reflection dir from sun object
        if (sun != null)
        {
            SunDir = sun.transform.forward;
            material.SetVector("_SunDir", SunDir);
        }

        if (this.renderReflection)
        {
            RenderObject();
        }

        if (followMainCamera)
        {
            Vector3 centerOffset;

            //centerOffset.x = Mathf.Floor (player.position.x / size.x) * size.x;
            //centerOffset.z = Mathf.Floor (player.position.z / size.z) * size.z;
            centerOffset.y = transform.position.y;
            //centerOffset.x =  (((int)player.position.x + 64) & ~127);
            //centerOffset.z =  (((int)player.position.z + 64) & ~127);

            //Optimized ocean tiles movement
            centerOffset.x = Mathf.Floor((player.position.x + size.x * 0.5f) * sizeInv.x) * size.x;
            centerOffset.z = Mathf.Floor((player.position.z + size.z * 0.5f) * sizeInv.y) * size.z;
            if (transform.position != centerOffset)
            {
                transform.position = centerOffset;
            }
        }


        float hhalf = height / 2f;
        float whalf = width / 2f;
        float time  = Time.time;

        for (int y = 0; y < height; y++)
        {
            for (int x = 0; x < width; x++)
            {
                int     idx   = width * y + x;
                float   yc    = y < hhalf ? y : -height + y;
                float   xc    = x < whalf ? x : -width + x;
                Vector2 vec_k = new Vector2(2.0f * Mathf.PI * xc / size.x, 2.0f * Mathf.PI * yc / size.z);

                float    sqrtMagnitude = (float)System.Math.Sqrt((vec_k.x * vec_k.x) + (vec_k.y * vec_k.y));
                float    iwkt          = (float)System.Math.Sqrt(9.81f * sqrtMagnitude) * time * speed;
                ComplexF coeffA        = new ComplexF((float)System.Math.Cos(iwkt), (float)System.Math.Sin(iwkt));
                ComplexF coeffB;
                coeffB.Re = coeffA.Re;
                coeffB.Im = -coeffA.Im;

                int ny = y > 0 ? height - y : 0;
                int nx = x > 0 ? width - x : 0;

                data [idx] = h0 [idx] * coeffA + h0[width * ny + nx].GetConjugate() * coeffB;
                t_x [idx]  = data [idx] * new ComplexF(0.0f, vec_k.x) - data [idx] * vec_k.y;

                // Choppy wave calculations
                if (x + y > 0)
                {
                    data [idx] += data [idx] * vec_k.x / sqrtMagnitude;
                }
            }
        }

        Fourier.FFT2(data, width, height, FourierDirection.Backward);
        Fourier.FFT2(t_x, width, height, FourierDirection.Backward);


        // Get base values for vertices and uv coordinates.
        if (baseHeight == null)
        {
            baseHeight = baseMesh.vertices;
            vertices   = new Vector3[baseHeight.Length];
            normals    = new Vector3[baseHeight.Length];
            tangents   = new Vector4[baseHeight.Length];
        }

        int   wh        = width * height;
        float scaleA    = choppy_scale / wh;
        float scaleB    = scale / wh;
        float scaleBinv = 1.0f / scaleB;

        for (int i = 0; i < wh; i++)
        {
            int iw = i + i / width;
            vertices [iw]    = baseHeight [iw];
            vertices [iw].x += data [i].Im * scaleA;
            vertices [iw].y  = data [i].Re * scaleB;

            normals [iw] = Vector3.Normalize(new Vector3(t_x [i].Re, scaleBinv, t_x [i].Im));

            if (((i + 1) % width) == 0)
            {
                int iwi    = iw + 1;
                int iwidth = i + 1 - width;
                vertices [iwi]    = baseHeight [iwi];
                vertices [iwi].x += data [iwidth].Im * scaleA;
                vertices [iwi].y  = data [iwidth].Re * scaleB;

                normals [iwi] = Vector3.Normalize(new Vector3(t_x [iwidth].Re, scaleBinv, t_x [iwidth].Im));
            }
        }

        int offset = g_width * (g_height - 1);

        for (int i = 0; i < g_width; i++)
        {
            int io  = i + offset;
            int mod = i % width;
            vertices [io]    = baseHeight [io];
            vertices [io].x += data [mod].Im * scaleA;
            vertices [io].y  = data [mod].Re * scaleB;

            normals [io] = Vector3.Normalize(new Vector3(t_x [mod].Re, scaleBinv, t_x [mod].Im));
        }

        int gwgh = g_width * g_height - 1;

        for (int i = 0; i < gwgh; i++)
        {
            //Need to preserve w in refraction/reflection mode
            if (!reflectionRefractionEnabled)
            {
                if (((i + 1) % g_width) == 0)
                {
                    tangents [i] = Vector3.Normalize((vertices [i - width + 1] + new Vector3(size.x, 0.0f, 0.0f) - vertices [i]));
                }
                else
                {
                    tangents [i] = Vector3.Normalize((vertices [i + 1] - vertices [i]));
                }

                tangents [i].w = 1.0f;
            }
            else
            {
                Vector3 tmp;                // = Vector3.zero;

                if (((i + 1) % g_width) == 0)
                {
                    tmp = Vector3.Normalize(vertices[i - width + 1] + new Vector3(size.x, 0.0f, 0.0f) - vertices [i]);
                }
                else
                {
                    tmp = Vector3.Normalize(vertices [i + 1] - vertices [i]);
                }

                tangents [i] = new Vector4(tmp.x, tmp.y, tmp.z, tangents [i].w);
            }
        }



        //Vector3 playerRelPos =  player.position - transform.position;

        //In reflection mode, use tangent w for foam strength
        if (reflectionRefractionEnabled)
        {
            for (int y = 0; y < g_height; y++)
            {
                for (int x = 0; x < g_width; x++)
                {
                    int item = x + g_width * y;
                    if (x + 1 >= g_width)
                    {
                        tangents [item].w = tangents [g_width * y].w;

                        continue;
                    }

                    if (y + 1 >= g_height)
                    {
                        tangents [item].w = tangents [x].w;

                        continue;
                    }

                    float right = vertices[(x + 1) + g_width * y].x - vertices[item].x;

                    float foam = right / (size.x / g_width);


                    if (foam < 0.0f)
                    {
                        tangents [item].w = 1f;
                    }
                    else if (foam < 0.5f)
                    {
                        tangents [item].w += 3.0f * Time.deltaTime;
                    }
                    else
                    {
                        tangents [item].w -= 0.4f * Time.deltaTime;
                    }

                    if (player != null)
                    {
                        Vector3 player2Vertex = (player.position - vertices[item] - transform.position);
                        // foam around boat
                        if (player2Vertex.x >= size.x)
                        {
                            player2Vertex.x -= size.x;
                        }

                        if (player2Vertex.x <= -size.x)
                        {
                            player2Vertex.x += size.x;
                        }

                        if (player2Vertex.z >= size.z)
                        {
                            player2Vertex.z -= size.z;
                        }

                        if (player2Vertex.z <= -size.z)
                        {
                            player2Vertex.z += size.z;
                        }
                        player2Vertex.y = 0;

                        if (player2Vertex.sqrMagnitude < wakeDistance * wakeDistance)
                        {
                            tangents[item].w += 3.0f * Time.deltaTime;
                        }
                    }


                    tangents [item].w = Mathf.Clamp(tangents[item].w, 0.0f, 2.0f);
                }
            }
        }

        tangents [gwgh] = Vector4.Normalize(vertices [gwgh] + new Vector3(size.x, 0.0f, 0.0f) - vertices [1]);

        for (int L0D = 0; L0D < max_LOD; L0D++)
        {
            int den       = (int)System.Math.Pow(2f, L0D);
            int itemcount = (int)((height / den + 1) * (width / den + 1));

            Vector4[] tangentsLOD = new Vector4[itemcount];
            Vector3[] verticesLOD = new Vector3[itemcount];
            Vector3[] normalsLOD  = new Vector3[itemcount];

            int idx = 0;

            for (int y = 0; y < g_height; y += den)
            {
                for (int x = 0; x < g_width; x += den)
                {
                    int idx2 = g_width * y + x;
                    verticesLOD [idx]  = vertices [idx2];
                    tangentsLOD [idx]  = tangents [idx2];
                    normalsLOD [idx++] = normals [idx2];
                }
            }
            for (int k = 0; k < tiles_LOD[L0D].Count; k++)
            {
                Mesh meshLOD = tiles_LOD [L0D][k];
                meshLOD.vertices = verticesLOD;
                meshLOD.normals  = normalsLOD;
                meshLOD.tangents = tangentsLOD;
            }
        }
    }
示例#6
0
 public DeblurFilter(UnmanagedImage reference, UnmanagedImage blurred)
     : this(Fourier.FFT2(reference), Fourier.FFT2(blurred))
 {
 }
示例#7
0
    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.P))
        {
            Application.CaptureScreenshot("Screenshot.png");
        }

        for (int y = 0; y < height; y++)
        {
            for (int x = 0; x < width; x++)
            {
                int     idx   = width * y + x;
                float   yc    = y < height / 2 ? y : -height + y;
                float   xc    = x < width / 2 ? x : -width + x;
                Vector2 vec_k = new Vector2(2.0f * Mathf.PI * xc / size.x, 2.0f * Mathf.PI * yc / size.z);

                float    iwkt   = disp(vec_k) * Time.time;
                ComplexF coeffA = new ComplexF(Mathf.Cos(iwkt), Mathf.Sin(iwkt));
                ComplexF coeffB = coeffA.GetConjugate();

                int ny = y > 0 ? height - y : 0;
                int nx = x > 0 ? width - x : 0;

                data[idx] = h0[idx] * coeffA + h0[width * ny + nx].GetConjugate() * coeffB;
                t_x[idx]  = data[idx] * new ComplexF(0.0f, vec_k.x) - data[idx] * vec_k.y;

                // Choppy wave calcuations
                if (x + y > 0)
                {
                    data[idx] += data[idx] * vec_k.x / vec_k.magnitude;
                }
            }
        }
        material_ocean.SetFloat("_BlendA", Mathf.Cos(Time.time) * 0.1f);
        material_ocean.SetFloat("_BlendB", Mathf.Sin(Time.time) * 0.5f);

        Fourier.FFT2(data, width, height, FourierDirection.Backward);
        Fourier.FFT2(t_x, width, height, FourierDirection.Backward);

        // Get base values for vertices and uv coordinates.
        if (baseHeight == null)
        {
            Mesh mesh = baseMesh;
            baseHeight = mesh.vertices;
            baseUV     = mesh.uv;

            int itemCount = baseHeight.Length;
            uvs      = new Vector2[itemCount];
            vertices = new Vector3[itemCount];
            normals  = new Vector3[itemCount];
            tangents = new Vector4[itemCount];
        }

        //Vector3 vertex;
        Vector3 uv;
        //Vector3 normal;
        float n_scale = size.x / width / scale;

        float scaleA    = choppy_scale / (width * height);
        float scaleB    = scale / (width * height);
        float scaleBinv = 1.0f / scaleB;

        for (int i = 0; i < width * height; i++)
        {
            int iw = i + i / width;
            vertices[iw]    = baseHeight[iw];
            vertices[iw].x += data[i].Im * scaleA;
            vertices[iw].y  = data[i].Re * scaleB;

            normals[iw] = new Vector3(t_x[i].Re, scaleBinv, t_x[i].Im).normalized;

            uv      = baseUV[iw];
            uv.x    = uv.x + Time.time * uv_speed;
            uvs[iw] = uv;


            if (!((i + 1) % width > 0))
            {
                vertices[iw + 1]    = baseHeight[iw + 1];
                vertices[iw + 1].x += data[i + 1 - width].Im * scaleA;
                vertices[iw + 1].y  = data[i + 1 - width].Re * scaleB;

                normals[iw + 1] = new Vector3(t_x[i + 1 - width].Re, scaleBinv, t_x[i + 1 - width].Im).normalized;

                uv          = baseUV[iw + 1];
                uv.x        = uv.x + Time.time * uv_speed;
                uvs[iw + 1] = uv;
            }
        }

        int offset = g_width * (g_height - 1);

        for (int i = 0; i < g_width; i++)
        {
            vertices[i + offset]    = baseHeight[i + offset];
            vertices[i + offset].x += data[i % width].Im * scaleA;
            vertices[i + offset].y  = data[i % width].Re * scaleB;

            normals[i + offset] = new Vector3(t_x[i % width].Re, scaleBinv, t_x[i % width].Im).normalized;

            uv              = baseUV[i + offset];
            uv.x            = uv.x - Time.time * uv_speed;
            uvs[i + offset] = uv;
        }

        for (int i = 0; i < g_width * g_height - 1; i++)
        {
            //Need to preserve w in refraction/reflection mode
            if (!reflectionRefractionEnabled)
            {
                if (((i + 1) % g_width) == 0)
                {
                    tangents[i] = (vertices[i - width + 1] + new Vector3(size.x, 0.0f, 0.0f) - vertices[i]).normalized;
                }
                else
                {
                    tangents[i] = (vertices[i + 1] - vertices[i]).normalized;
                }

                tangents[i].w = 1.0f;
            }
            else
            {
                Vector3 tmp = Vector3.zero;

                if (((i + 1) % g_width) == 0)
                {
                    tmp = (vertices[i - width + 1] + new Vector3(size.x, 0.0f, 0.0f) - vertices[i]).normalized;
                }
                else
                {
                    tmp = (vertices[i + 1] - vertices[i]).normalized;
                }

                tangents[i] = new Vector4(tmp.x, tmp.y, tmp.z, tangents[i].w);
            }
        }

        //In reflection mode, use tangent w for foam strength
        if (reflectionRefractionEnabled)
        {
            for (int y = 0; y < g_height; y++)
            {
                for (int x = 0; x < g_width; x++)
                {
                    if (x + 1 >= g_width)
                    {
                        tangents[x + g_width * y].w = tangents[g_width * y].w;

                        continue;
                    }

                    if (y + 1 >= g_height)
                    {
                        tangents[x + g_width * y].w = tangents[x].w;

                        continue;
                    }

                    Vector3 right = vertices[(x + 1) + g_width * y] - vertices[x + g_width * y];
                    Vector3 back  = vertices[x + g_width * y] - vertices[x + g_width * (y + 1)];

                    float foam = right.x / (size.x / g_width);


                    if (foam < 0.0f)
                    {
                        tangents[x + g_width * y].w = 1;
                    }
                    else if (foam < 0.5f)
                    {
                        tangents[x + g_width * y].w += 2 * Time.deltaTime;
                    }
                    else
                    {
                        tangents[x + g_width * y].w -= 0.5f * Time.deltaTime;
                    }

                    tangents[x + g_width * y].w = Mathf.Clamp(tangents[x + g_width * y].w / foamTime, 0.0f, 2.0f);
                }
            }
        }

        tangents[g_width * g_height - 1] = (vertices[g_width * g_height - 1] + new Vector3(size.x, 0.0f, 0.0f) - vertices[1]).normalized;

        //~ LOD=0;
        for (int LOD = 0; LOD < max_LOD; LOD++)
        {
            int den       = (int)Mathf.Pow(2, LOD);
            int itemcount = (height / den + 1) * (width / den + 1);

            Vector4[] tangentsLOD = new Vector4[itemcount];
            Vector3[] verticesLOD = new Vector3[itemcount];
            Vector3[] normalsLOD  = new Vector3[itemcount];
            Vector2[] uvLOD       = new Vector2[(height / (int)Mathf.Pow(2, LOD) + 1) * (width / (int)Mathf.Pow(2, LOD) + 1)];
            int       idx         = 0;

            for (int y = 0; y < g_height; y += den)
            {
                for (int x = 0; x < g_width; x += den)
                {
                    int idx2 = g_width * y + x;
                    verticesLOD[idx]  = vertices[idx2];
                    uvLOD[idx]        = uvs[g_width * y + x];
                    tangentsLOD[idx]  = tangents[idx2];
                    normalsLOD[idx++] = normals[idx2];
                }
            }
            for (int k = 0; k < tiles_LOD[LOD].Count; k++)
            {
                Mesh meshLOD = tiles_LOD[LOD][k];
                meshLOD.vertices = verticesLOD;
                meshLOD.normals  = normalsLOD;
                meshLOD.uv       = uvLOD;
                meshLOD.tangents = tangentsLOD;
            }
        }
        //oceansize=width*(max_LOD*2+1);
        float width_LOD2 = 175 * s;
        //transform.position.x=mycam.transform.localPosition.x;
        float tmpx = Mathf.RoundToInt(mycam.transform.position.x / width_LOD2);
        float tmpz = Mathf.RoundToInt(mycam.transform.position.z / width_LOD2);

        tmpx = tmpx * width_LOD2 - (width_LOD2 / 2);
        tmpz = tmpz * width_LOD2 - (width_LOD2 / 2);
        //tmpx-=Mathf.RoundToInt(width_LOD2);
        //tmpz-=Mathf.RoundToInt(width_LOD2);

        //~ transform.position.x=tmpx;
        //~ transform.position.z=tmpz;

        transform.position = new Vector3(tmpx, transform.position.y, tmpz);

        //transform.position.z=mycam.transform.localPosition.z*1000;
    }
示例#8
0
        public iTemplate(Bitmap myImage)
        {
            //BitmapFilter.GrayScale(myImage);
            BitmapFilter.FixHistogram(ref myImage);
            //   myImage.Save("FixedHistogram.bmp", System.Drawing.Imaging.ImageFormat.Bmp);
            BitmapFilter.Binarize(ref myImage, 110);
            //    myImage.Save("Binarized.bmp", System.Drawing.Imaging.ImageFormat.Bmp);
            //BitmapFilter.GaussianBlur(myImage, 1);


            /******************************************************/
            CImage cimage = new CImage(myImage);
            float  scale  = 1f / (float)Math.Sqrt(cimage.Width * cimage.Height);

            ComplexF[] data = cimage.Data;

            int offset = 0;

            for (int y = 0; y < cimage.Height; y++)
            {
                for (int x = 0; x < cimage.Width; x++)
                {
                    if (((x + y) & 0x1) != 0)
                    {
                        data[offset] *= -1;
                    }
                    offset++;
                }
            }

            Fourier.FFT2(data, cimage.Width, cimage.Height, FourierDirection.Forward);

            cimage.FrequencySpace = true;

            for (int i = 0; i < data.Length; i++)
            {
                data[i] *= scale;
            }

            myImage = cimage.ToBitmap();

            //       myImage.Save("FFT.bmp", System.Drawing.Imaging.ImageFormat.Bmp);
            //pictureBoxFiltred.Size = new System.Drawing.Size(myImage.Width, myImage.Height);
            /******************************************************/


            Bitmap zerImage = new Bitmap(zerSize, zerSize);
            int    ow, oh;

            ow = myImage.Width / 2 - zerSize / 2;
            oh = myImage.Height / 2 - zerSize / 2;

            for (int y = 0; y < zerSize; y++)
            {
                for (int x = 0; x < zerSize; x++)
                {
                    zerImage.SetPixel(x, y, myImage.GetPixel(x + ow, y + oh));
                }
            }

            ZernikeDesc zernikeDesc = new ZernikeDesc(zerImage);

            zerCoefficients = zernikeDesc.Process();
        }
示例#9
0
        /// <summary>
        /// Update is called once per frame.
        /// </summary>
        private void Update()
        {
            if (!simulationEnabled)
            {
                return;
            }

            // Calculate mesh vertices, uv and tangents.
            float halfWidth  = tilePolygonWidth / 2.0f;
            float halfHeight = tilePolygonHeight / 2.0f;
            float time       = Time.time;

            for (int y = 0; y < tilePolygonHeight; ++y)
            {
                for (int x = 0; x < tilePolygonWidth; ++x)
                {
                    int     idx   = tilePolygonWidth * y + x;
                    float   yCopy = y < halfHeight ? y : y - tilePolygonHeight;
                    float   xCopy = x < halfWidth ? x : x - tilePolygonWidth;
                    Vector2 vecK  = new Vector2(2.0f * Mathf.PI * xCopy / oceanTileSize.x, 2.0f * Mathf.PI * yCopy / oceanTileSize.z);

                    float    sqrtMagnitude = (float)Math.Sqrt(Mathf.Pow(vecK.x, 2.0f) + Mathf.Pow(vecK.y, 2.0f));
                    float    offset        = Mathf.Sqrt(GRAVITY_ACCELERATION * sqrtMagnitude) * time * waveSpeed;
                    ComplexF complexFA     = new ComplexF(Mathf.Cos(offset), Mathf.Sin(offset));
                    ComplexF complexFB;
                    complexFB.Re = complexFA.Re;
                    complexFB.Im = -complexFA.Im;

                    int nY = y > 0 ? tilePolygonHeight - y : 0;
                    int nX = x > 0 ? tilePolygonWidth - x : 0;

                    waterHeightData[idx] = vertexSpectra[idx] * complexFA + vertexSpectra[tilePolygonWidth * nY + nX].GetConjugate() * complexFB;
                    tangentX[idx]        = waterHeightData[idx] * new ComplexF(0.0f, vecK.x) - waterHeightData[idx] * vecK.y;

                    // Choppy wave calculation.
                    if (x + y > 0)
                    {
                        waterHeightData[idx] += waterHeightData[idx] * vecK.x / sqrtMagnitude;
                    }
                }
            }

            Fourier.FFT2(waterHeightData, tilePolygonWidth, tilePolygonHeight, FourierDirection.Backward);
            Fourier.FFT2(tangentX, tilePolygonWidth, tilePolygonHeight, FourierDirection.Backward);

            // Get base values for vertices and uv coordinates.
            if (baseHeights == null)
            {
                baseHeights = baseMesh.vertices;
                vertices    = new Vector3[baseHeights.Length];
                normals     = new Vector3[baseHeights.Length];
                tangents    = new Vector4[baseHeights.Length];
            }

            int   area             = tilePolygonWidth * tilePolygonHeight;
            float scaleX           = choppyScale / area;
            float scaleY           = waveScaleRealTime / area;
            float scaleYReciprocal = MathUtility.GetReciprocal(scaleY);

            for (int i = 0; i < area; ++i)
            {
                int index = i + i / tilePolygonWidth;
                vertices[index]    = baseHeights[index];
                vertices[index].x += waterHeightData[i].Im * scaleX;
                vertices[index].y  = waterHeightData[i].Re * scaleY;

                normals[index] = Vector3.Normalize(new Vector3(tangentX[i].Re, scaleYReciprocal, tangentX[i].Im));

                if ((i + 1) % tilePolygonWidth == 0)
                {
                    int indexPlus = index + 1;
                    int iWidth    = i + 1 - tilePolygonWidth;
                    vertices[indexPlus]    = baseHeights[indexPlus];
                    vertices[indexPlus].x += waterHeightData[iWidth].Im * scaleX;
                    vertices[indexPlus].y  = waterHeightData[iWidth].Re * scaleY;

                    normals[indexPlus] = Vector3.Normalize(new Vector3(tangentX[iWidth].Re, scaleYReciprocal, tangentX[iWidth].Im));
                }
            }

            int indexOffset = geometryWidth * (geometryHeight - 1);

            for (int i = 0; i < geometryWidth; ++i)
            {
                int index = i + indexOffset;
                int mod   = i % tilePolygonWidth;

                vertices[index]    = baseHeights[index];
                vertices[index].x += waterHeightData[mod].Im * scaleX;
                vertices[index].y  = waterHeightData[mod].Re * scaleY;

                normals[index] = Vector3.Normalize(new Vector3(tangentX[mod].Re, scaleYReciprocal, tangentX[mod].Im));
            }

            int geometryArea = geometryWidth * geometryHeight - 1;

            for (int i = 0; i < geometryArea; ++i)
            {
                Vector3 tmp;

                if ((i + 1) % geometryWidth == 0)
                {
                    tmp = Vector3.Normalize(vertices[i - tilePolygonWidth + 1] + new Vector3(oceanTileSize.x, 0.0f, 0.0f) - vertices[i]);
                }
                else
                {
                    tmp = Vector3.Normalize(vertices[i + 1] - vertices[i]);
                }

                tangents[i] = new Vector4(tmp.x, tmp.y, tmp.z, tangents[i].w);
            }

            for (int y = 0; y < geometryHeight; ++y)
            {
                for (int x = 0; x < geometryWidth; ++x)
                {
                    int index = x + geometryWidth * y;

                    if (x + 1 >= geometryWidth)
                    {
                        tangents[index].w = tangents[geometryWidth * y].w;
                        continue;
                    }

                    if (y + 1 >= geometryHeight)
                    {
                        tangents[index].w = tangents[x].w;
                        continue;
                    }

                    float right = vertices[x + 1 + geometryWidth * y].x - vertices[index].x;
                    float foam  = right / (oceanTileSize.x / geometryWidth);

                    if (foam < 0.0f)
                    {
                        tangents[index].w = 1.0f;
                    }
                    else if (foam < 0.5f)
                    {
                        tangents[index].w += 3.0f * Time.deltaTime;
                    }
                    else
                    {
                        tangents[index].w -= 0.4f * Time.deltaTime;
                    }

                    tangents[index].w = Mathf.Clamp(tangents[index].w, 0.0f, 2.0f);
                }
            }

            tangents[geometryArea] = Vector4.Normalize(vertices[geometryArea] + new Vector3(oceanTileSize.x, 0.0f, 0.0f) - vertices[1]);

            for (int level = 0; level < MAX_LOD; ++level)
            {
                int pow    = (int)Math.Pow(2.0f, level);
                int length = (int)((tilePolygonHeight / pow + 1) * (tilePolygonWidth / pow + 1));

                Vector4[] tangentsLOD = new Vector4[length];
                Vector3[] verticesLOD = new Vector3[length];
                Vector3[] normalsLOD  = new Vector3[length];

                int index = 0;

                for (int y = 0; y < geometryHeight; y += pow)
                {
                    for (int x = 0; x < geometryWidth; x += pow)
                    {
                        int indexTemp = geometryWidth * y + x;
                        verticesLOD[index]  = vertices[indexTemp];
                        tangentsLOD[index]  = tangents[indexTemp];
                        normalsLOD[index++] = normals[indexTemp];
                    }
                }

                for (int i = 0, count = tilesLOD[level].Count; i < count; ++i)
                {
                    Mesh meshLOD = tilesLOD[level][i];
                    meshLOD.vertices = verticesLOD;
                    meshLOD.normals  = normalsLOD;
                    meshLOD.tangents = tangentsLOD;
                }
            }

            if (reflectionEnabled)
            {
                RenderReflectionAndRefraction();
            }
        }