Full Code of ufna/VaOcean for AI

archive_UE4.12 a01274e0aac0 cached
30 files
60.8 KB
18.1k tokens
32 symbols
1 requests
Download .txt
Repository: ufna/VaOcean
Branch: archive_UE4.12
Commit: a01274e0aac0
Files: 30
Total size: 60.8 KB

Directory structure:
gitextract_xwtm81v2/

├── .gitignore
├── Content/
│   ├── Blueprints/
│   │   ├── OceanSimulator.uasset
│   │   └── OceanSimulator_Debug.uasset
│   ├── Maps/
│   │   └── Level_Test.umap
│   ├── Materials/
│   │   ├── MI_OceanCS_Example.uasset
│   │   ├── M_FFT_Debug.uasset
│   │   └── M_OceanCS.uasset
│   ├── Meshes/
│   │   └── OceanSurface_Near.uasset
│   └── Textures/
│       ├── RT_Displacement.uasset
│       ├── RT_Gradient.uasset
│       ├── RT_Spectrum_Height.uasset
│       ├── RT_Spectrum_Normals.uasset
│       └── T_Noise_Perline.uasset
├── LICENSE
├── README.md
├── Shaders/
│   ├── VaOcean_CS.usf
│   ├── VaOcean_FFT.usf
│   └── VaOcean_VS_PS.usf
├── Source/
│   └── VaOceanPlugin/
│       ├── Classes/
│       │   ├── VaOceanRadixFFT.h
│       │   ├── VaOceanShaders.h
│       │   ├── VaOceanSimulator.h
│       │   └── VaOceanTypes.h
│       ├── Private/
│       │   ├── VaOceanPlugin.cpp
│       │   ├── VaOceanPluginPrivatePCH.h
│       │   ├── VaOceanRadixFFT.cpp
│       │   ├── VaOceanShaders.cpp
│       │   └── VaOceanSimulator.cpp
│       ├── Public/
│       │   └── IVaOceanPlugin.h
│       └── VaOceanPlugin.Build.cs
└── VaOceanPlugin.uplugin

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
# Compiled Object files
*.slo
*.lo
*.o
*.obj

# Compiled Dynamic libraries
*.so
*.dylib
*.dll

# Compiled Static libraries
*.lai
*.la
*.a
*.lib

# Executables
*.exe
*.out
*.app
/Binaries/
/Intermediate/


================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) 2014 Vladimir Alyamkin

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

================================================
FILE: README.md
================================================
Welcome to the VaOcean source code!
===================================

**Attn.! This branch contains archived version of plugin for UE 4.12 based on [NVIDIA SDK sample](https://developer.nvidia.com/dx11-samples) "FFT Ocean". It's deprecated and lives here for history only.**

----------

VaOcean is the ocean surface simulation plugin for [Unreal Engine 4](https://www.unrealengine.com/).

The plugin includes:

* Component that renders displacement and gradient (normal) maps in real time
* Sample content, including water shader and grid meshes to be used on scene
* Set of global shaders that perform FFT calculation and other tech stuff on GPU

Check the **[Wiki](https://github.com/ufna/VaOcean/wiki)** tab to know more about the plugin.

Current version: **0.4 Alpha 6 Hotfix 1**

![SCREENSHOT](SCREENSHOT.jpg)


Legal info
----------

Unreal® is a trademark or registered trademark of Epic Games, Inc. in the United States of America and elsewhere. Unreal® Engine, Copyright 1998 – 2014, Epic Games, Inc. All rights reserved.


References
----------

1. Tessendorf, Jerry. Simulating Ocean Water. In SIGGRAPH 2002 Course Notes #9 (Simulating Nature: Realistic and Interactive Techniques), ACM Press.

1. Phillips, O.M. 1957. On the generation of waves by turbulent wind. Journal of Fluid Mechanics. 2 (5): 417–445.



================================================
FILE: Shaders/VaOcean_CS.usf
================================================
// Copyright 2014 Vladimir Alyamkin. All Rights Reserved.

#include "Common.usf"

#define PI 3.1415926536f
#define BLOCK_SIZE_X 16
#define BLOCK_SIZE_Y 16

// Immutable
uint g_ActualDim;
uint g_InWidth;
uint g_OutWidth;
uint g_OutHeight;
uint g_DtxAddressOffset;
uint g_DtyAddressOffset;

// Buffers
StructuredBuffer<float2>	g_InputH0;
StructuredBuffer<float>		g_InputOmega;
RWStructuredBuffer<float2>	g_OutputHt;


//////////////////////////////////////////////////////////////////////////
// Pre-FFT data preparation: H(0) -> H(t)

[numthreads(BLOCK_SIZE_X, BLOCK_SIZE_Y, 1)]
void UpdateSpectrumCS(uint3 DTid : SV_DispatchThreadID)
{
	int in_index = DTid.y * g_InWidth + DTid.x;
	int in_mindex = (g_ActualDim - DTid.y) * g_InWidth + (g_ActualDim - DTid.x);
	int out_index = DTid.y * g_OutWidth + DTid.x;

	// H(0) -> H(t)
	float2 h0_k  = g_InputH0[in_index];
	float2 h0_mk = g_InputH0[in_mindex];
	float sin_v, cos_v;
	sincos(g_InputOmega[in_index] * PerFrameSp.Time, sin_v, cos_v);

	float2 ht;
	ht.x = (h0_k.x + h0_mk.x) * cos_v - (h0_k.y + h0_mk.y) * sin_v;
	ht.y = (h0_k.x - h0_mk.x) * sin_v + (h0_k.y - h0_mk.y) * cos_v;

	// H(t) -> Dx(t), Dy(t)
	float kx = DTid.x - g_ActualDim * 0.5f;
	float ky = DTid.y - g_ActualDim * 0.5f;
	float sqr_k = kx * kx + ky * ky;
	float rsqr_k = 0;
	if (sqr_k > 1e-12f)
	{
		rsqr_k = 1 / sqrt(sqr_k);
	}
	
	kx *= rsqr_k;
	ky *= rsqr_k;
	float2 dt_x = float2(ht.y * kx, -ht.x * kx);
	float2 dt_y = float2(ht.y * ky, -ht.x * ky);

	if ((DTid.x < g_OutWidth) && (DTid.y < g_OutHeight))
	{
		g_OutputHt[out_index] = ht;
		g_OutputHt[out_index + g_DtxAddressOffset] = dt_x;
		g_OutputHt[out_index + g_DtyAddressOffset] = dt_y;
	}
}


================================================
FILE: Shaders/VaOcean_FFT.usf
================================================
// Copyright 2014 Vladimir Alyamkin. All Rights Reserved.

#include "Common.usf"

#define COS_PI_4_16 0.70710678118654752440084436210485f
#define TWIDDLE_1_8 COS_PI_4_16, -COS_PI_4_16
#define TWIDDLE_3_8 -COS_PI_4_16, -COS_PI_4_16

#define COHERENCY_GRANULARITY 128

// Source and destination buffers
StructuredBuffer<float2>	g_SrcData;
RWStructuredBuffer<float2>	g_DstData;


//////////////////////////////////////////////////////////////////////////
// FFT butterfly helper functions

void FT2(inout float2 a, inout float2 b)
{
	float t;

	t = a.x;
	a.x += b.x;
	b.x = t - b.x;

	t = a.y;
	a.y += b.y;
	b.y = t - b.y;
}

void CMUL_forward(inout float2 a, float bx, float by)
{
	float t = a.x;
	a.x = t * bx - a.y * by;
	a.y = t * by + a.y * bx;
}

void UPD_forward(inout float2 a, inout float2 b)
{
	float A = a.x;
	float B = b.y;

	a.x += b.y;
	b.y = a.y + b.x;
	a.y -= b.x;
	b.x = A - B;
}

void FFT_forward_4(inout float2 D[8])
{
	FT2(D[0], D[2]);
	FT2(D[1], D[3]);
	FT2(D[0], D[1]);

	UPD_forward(D[2], D[3]);
}

void FFT_forward_8(inout float2 D[8])
{
	FT2(D[0], D[4]);
	FT2(D[1], D[5]);
	FT2(D[2], D[6]);
	FT2(D[3], D[7]);

	UPD_forward(D[4], D[6]);
	UPD_forward(D[5], D[7]);

	CMUL_forward(D[5], TWIDDLE_1_8);
	CMUL_forward(D[7], TWIDDLE_3_8);

	FFT_forward_4(D);
	FT2(D[4], D[5]);
	FT2(D[6], D[7]);
}

void TWIDDLE(inout float2 d, float phase)
{
	float tx, ty;

	sincos(phase, ty, tx);
	float t = d.x;
	d.x = t * tx - d.y * ty;
	d.y = t * ty + d.y * tx;
}

void TWIDDLE_8(inout float2 D[8], float phase)
{
	TWIDDLE(D[4], 1 * phase);
	TWIDDLE(D[2], 2 * phase);
	TWIDDLE(D[6], 3 * phase);
	TWIDDLE(D[1], 4 * phase);
	TWIDDLE(D[5], 5 * phase);
	TWIDDLE(D[3], 6 * phase);
	TWIDDLE(D[7], 7 * phase);
}


//////////////////////////////////////////////////////////////////////////
// Radix FFT compute shaders

[numthreads(COHERENCY_GRANULARITY, 1, 1)]
void Radix008A_CS(uint3 thread_id : SV_DispatchThreadID)
{
	if (thread_id.x >= PerFrameFFT.ThreadCount)
		return;

	// Fetch 8 complex numbers
	float2 D[8];

	uint i;
	uint imod = thread_id & (PerFrameFFT.istride - 1);
	uint iaddr = ((thread_id - imod) << 3) + imod;
	for (i = 0; i < 8; i++)
	{
		D[i] = g_SrcData[iaddr + i * PerFrameFFT.istride];
	}

	// Math
	FFT_forward_8(D);
	uint p = thread_id & (PerFrameFFT.istride - PerFrameFFT.pstride);
	float phase = PerFrameFFT.PhaseBase * (float)p;
	TWIDDLE_8(D, phase);

	// Store the result
	uint omod = thread_id & (PerFrameFFT.ostride - 1);
	uint oaddr = ((thread_id - omod) << 3) + omod;
	g_DstData[oaddr + 0 * PerFrameFFT.ostride] = D[0];
	g_DstData[oaddr + 1 * PerFrameFFT.ostride] = D[4];
	g_DstData[oaddr + 2 * PerFrameFFT.ostride] = D[2];
	g_DstData[oaddr + 3 * PerFrameFFT.ostride] = D[6];
	g_DstData[oaddr + 4 * PerFrameFFT.ostride] = D[1];
	g_DstData[oaddr + 5 * PerFrameFFT.ostride] = D[5];
	g_DstData[oaddr + 6 * PerFrameFFT.ostride] = D[3];
	g_DstData[oaddr + 7 * PerFrameFFT.ostride] = D[7];
}

[numthreads(COHERENCY_GRANULARITY, 1, 1)]
void Radix008A_CS2(uint3 thread_id : SV_DispatchThreadID)
{
	if(thread_id.x >= PerFrameFFT.ThreadCount)
		return;

	// Fetch 8 complex numbers
	uint i;
	float2 D[8];
	uint iaddr = thread_id << 3;
	for (i = 0; i < 8; i++)
	{
		D[i] = g_SrcData[iaddr + i];
	}

	// Math
	FFT_forward_8(D);

	// Store the result
	uint omod = thread_id & (PerFrameFFT.ostride - 1);
	uint oaddr = ((thread_id - omod) << 3) + omod;
	g_DstData[oaddr + 0 * PerFrameFFT.ostride] = D[0];
	g_DstData[oaddr + 1 * PerFrameFFT.ostride] = D[4];
	g_DstData[oaddr + 2 * PerFrameFFT.ostride] = D[2];
	g_DstData[oaddr + 3 * PerFrameFFT.ostride] = D[6];
	g_DstData[oaddr + 4 * PerFrameFFT.ostride] = D[1];
	g_DstData[oaddr + 5 * PerFrameFFT.ostride] = D[5];
	g_DstData[oaddr + 6 * PerFrameFFT.ostride] = D[3];
	g_DstData[oaddr + 7 * PerFrameFFT.ostride] = D[7];
}


================================================
FILE: Shaders/VaOcean_VS_PS.usf
================================================
// Copyright 2014 Vladimir Alyamkin. All Rights Reserved.

#include "Common.usf"


//////////////////////////////////////////////////////////////////////////
// Vertex shaders

void QuadVS(
	in float4 InPosition : ATTRIBUTE0,
	in float2 InTexCoord : ATTRIBUTE1,
	out float2 OutTexCoord : TEXCOORD0,
	out float4 OutPosition : SV_POSITION)
{
	OutPosition = InPosition;
	OutTexCoord.x = 0.5f + InPosition.x * 0.5f;
	OutTexCoord.y = 0.5f - InPosition.y * 0.5f;
}


//////////////////////////////////////////////////////////////////////////
// Pixel shaders

// Immutable
uint g_ActualDim;
uint g_InWidth;
uint g_OutWidth;
uint g_OutHeight;
uint g_DtxAddressOffset;
uint g_DtyAddressOffset;

// The following three should contains only real numbers. But we have only C2C FFT now.
StructuredBuffer<float2> g_InputDxyz;

// Post-FFT data wrap up: Dx, Dy, Dz -> Displacement
void UpdateDisplacementPS(float2 UV : TEXCOORD0, out float4 OutColor : SV_Target0)
{
	uint index_x = (uint)(UV.x * (float)g_OutWidth);
	uint index_y = (uint)(UV.y * (float)g_OutHeight);
	uint addr = g_OutWidth * index_y + index_x;

	// cos(pi * (m1 + m2))
	int sign_correction = ((index_x + index_y) & 1) ? -1 : 1;

	float dx = g_InputDxyz[addr + g_DtxAddressOffset].x * sign_correction * PerFrameDisp.ChoppyScale;
	float dy = g_InputDxyz[addr + g_DtyAddressOffset].x * sign_correction * PerFrameDisp.ChoppyScale;
	float dz = g_InputDxyz[addr].x * sign_correction;

	OutColor = float4(dx, dy, dz, 1);
}


// Textures and sampling states
Texture2D 		DisplacementMap;
SamplerState 	DisplacementMapSampler;

// Displacement -> Normal, Folding
void GenGradientFoldingPS(float2 UV : TEXCOORD0, out float4 OutColor : SV_Target0)
{
	// Sample neighbour texels
	float2 one_texel = float2(1.0f / (float)g_OutWidth, 1.0f / (float)g_OutHeight);

	float2 tc_left  = float2(UV.x - one_texel.x, UV.y);
	float2 tc_right = float2(UV.x + one_texel.x, UV.y);
	float2 tc_back  = float2(UV.x, UV.y - one_texel.y);
	float2 tc_front = float2(UV.x, UV.y + one_texel.y);

	float3 displace_left  = DisplacementMap.Sample(DisplacementMapSampler, tc_left).xyz;
	float3 displace_right = DisplacementMap.Sample(DisplacementMapSampler, tc_right).xyz;
	float3 displace_back  = DisplacementMap.Sample(DisplacementMapSampler, tc_back).xyz;
	float3 displace_front = DisplacementMap.Sample(DisplacementMapSampler, tc_front).xyz;
	
	// Do not store the actual normal value. Using gradient instead, which preserves two differential values.
	float2 gradient = {-(displace_right.z - displace_left.z), -(displace_front.z - displace_back.z)};
	

	// Calculate Jacobian corelation from the partial differential of height field
	float2 Dx = (displace_right.xy - displace_left.xy) * PerFrameDisp.ChoppyScale * PerFrameDisp.GridLen;
	float2 Dy = (displace_front.xy - displace_back.xy) * PerFrameDisp.ChoppyScale * PerFrameDisp.GridLen;
	float J = (1.0f + Dx.x) * (1.0f + Dy.y) - Dx.y * Dy.x;

	// Practical subsurface scale calculation: max[0, (1 - J) + Amplitude * (2 * Coverage - 1)].
	float fold = max(1.0f - J, 0);

	// Output
	OutColor = float4(gradient, 0, fold);
}


================================================
FILE: Source/VaOceanPlugin/Classes/VaOceanRadixFFT.h
================================================
// Copyright 2014-2016 Vladimir Alyamkin. All Rights Reserved.

#pragma once

#include "VaOceanPluginPrivatePCH.h"
#include "VaOceanRadixFFT.generated.h"

/** Memory access coherency (in threads) */
#define COHERENCY_GRANULARITY 128

/** Common constants */
#define TWO_PI 6.283185307179586476925286766559

#define FFT_DIMENSIONS 3U
#define FFT_PLAN_SIZE_LIMIT (1U << 27)

#define FFT_FORWARD -1
#define FFT_INVERSE 1

#define FFT_PARAM_SETS 6

/** Per frame parameters for FRadix008A_CS shader */
USTRUCT()
struct FRadix008A_CSPerFrame
{
	GENERATED_USTRUCT_BODY()

	uint32 ThreadCount;
	uint32 ostride;
	uint32 istride;
	uint32 pstride;
	float PhaseBase;
};

/** Radix FFT data (for 512x512 buffer size) */
USTRUCT()
struct FRadixPlan512
{
	GENERATED_USTRUCT_BODY()

	// More than one array can be transformed at same time
	uint32 Slices;

	// For 512x512 config, we need 6 sets of parameters
	FRadix008A_CSPerFrame PerFrame[FFT_PARAM_SETS];

	// Temporary buffers
	FStructuredBufferRHIRef pBuffer_Tmp;
	FUnorderedAccessViewRHIRef pUAV_Tmp;
	FShaderResourceViewRHIRef pSRV_Tmp;
};


void RadixCreatePlan(FRadixPlan512* Plan, uint32 Slices);
void RadixDestroyPlan(FRadixPlan512* Plan);

void RadixCompute(	FRHICommandListImmediate& RHICmdList,
					FRadixPlan512* Plan,
					FUnorderedAccessViewRHIRef pUAV_Dst,
					FShaderResourceViewRHIRef pSRV_Dst, 
					FShaderResourceViewRHIRef pSRV_Src);


================================================
FILE: Source/VaOceanPlugin/Classes/VaOceanShaders.h
================================================
// Copyright 2014-2016 Vladimir Alyamkin. All Rights Reserved.

#pragma once

#include "VaOceanPluginPrivatePCH.h"
#include "VaOceanShaders.generated.h"

#define HALF_SQRT_2	0.7071068f
#define GRAV_ACCEL	981.0f	// The acceleration of gravity, cm/s^2

#define BLOCK_SIZE_X 16
#define BLOCK_SIZE_Y 16


//////////////////////////////////////////////////////////////////////////
// UpdateSpectrumCS compute shader

BEGIN_UNIFORM_BUFFER_STRUCT(FUpdateSpectrumUniformParameters, )
	DECLARE_UNIFORM_BUFFER_STRUCT_MEMBER(float, Time)
END_UNIFORM_BUFFER_STRUCT(FUpdateSpectrumUniformParameters)

typedef TUniformBufferRef<FUpdateSpectrumUniformParameters> FUpdateSpectrumUniformBufferRef;

/** Immutable parameters for UpdateSpectrumCS shader*/
USTRUCT()
struct FUpdateSpectrumCSImmutable
{
	GENERATED_USTRUCT_BODY()

	uint32 g_ActualDim;
	uint32 g_InWidth;
	uint32 g_OutWidth;
	uint32 g_OutHeight;
	uint32 g_DtxAddressOffset;
	uint32 g_DtyAddressOffset;
};

/** Per frame parameters for UpdateSpectrumCS shader */
USTRUCT()
struct FUpdateSpectrumCSPerFrame
{
	GENERATED_USTRUCT_BODY()

	FShaderResourceViewRHIRef m_pSRV_H0;
	FShaderResourceViewRHIRef m_pSRV_Omega;
	FUnorderedAccessViewRHIRef m_pUAV_Ht;

	// Used to pass params into render thread
	float g_Time;
	float g_ChoppyScale;
};

/**
 * H(0) -> H(t), D(x,t), D(y,t)
 */
class FUpdateSpectrumCS : public FGlobalShader
{
	DECLARE_SHADER_TYPE(FUpdateSpectrumCS, Global)

public:
	static bool ShouldCache(EShaderPlatform Platform)
	{
		return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM5);
	}

	FUpdateSpectrumCS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
		: FGlobalShader(Initializer)
	{
		ActualDim.Bind(Initializer.ParameterMap, TEXT("g_ActualDim"), SPF_Mandatory);
		InWidth.Bind(Initializer.ParameterMap, TEXT("g_InWidth"), SPF_Mandatory);
		OutWidth.Bind(Initializer.ParameterMap, TEXT("g_OutWidth"), SPF_Mandatory);
		OutHeight.Bind(Initializer.ParameterMap, TEXT("g_OutHeight"), SPF_Mandatory);
		DtxAddressOffset.Bind(Initializer.ParameterMap, TEXT("g_DtxAddressOffset"), SPF_Mandatory);
		DtyAddressOffset.Bind(Initializer.ParameterMap, TEXT("g_DtyAddressOffset"), SPF_Mandatory);

		InputH0.Bind(Initializer.ParameterMap, TEXT("g_InputH0"), SPF_Mandatory);
		InputOmega.Bind(Initializer.ParameterMap, TEXT("g_InputOmega"), SPF_Mandatory);

		OutputHtRW.Bind(Initializer.ParameterMap, TEXT("g_OutputHt"), SPF_Mandatory);
	}

	FUpdateSpectrumCS()
	{
	}

	void SetParameters(
		FRHICommandList& RHICmdList,
		uint32 ParamActualDim,
		uint32 ParamInWidth,
		uint32 ParamOutWidth,
		uint32 ParamOutHeight,
		uint32 ParamDtxAddressOffset,
		uint32 ParamDtyAddressOffset
		)
	{
		FComputeShaderRHIParamRef ComputeShaderRHI = GetComputeShader();

		SetShaderValue(RHICmdList, ComputeShaderRHI, ActualDim, ParamActualDim);
		SetShaderValue(RHICmdList, ComputeShaderRHI, InWidth, ParamInWidth);
		SetShaderValue(RHICmdList, ComputeShaderRHI, OutWidth, ParamOutWidth);
		SetShaderValue(RHICmdList, ComputeShaderRHI, OutHeight, ParamOutHeight);
		SetShaderValue(RHICmdList, ComputeShaderRHI, DtxAddressOffset, ParamDtxAddressOffset);
		SetShaderValue(RHICmdList, ComputeShaderRHI, DtyAddressOffset, ParamDtyAddressOffset);
	}

	void SetParameters(
		FRHICommandList& RHICmdList,
		const FUpdateSpectrumUniformBufferRef& UniformBuffer,
		FShaderResourceViewRHIRef ParamInputH0,
		FShaderResourceViewRHIRef ParamInputOmega
		)
	{
		FComputeShaderRHIParamRef ComputeShaderRHI = GetComputeShader();

		SetUniformBufferParameter(RHICmdList, ComputeShaderRHI, GetUniformBufferParameter<FUpdateSpectrumUniformParameters>(), UniformBuffer);

		RHICmdList.SetShaderResourceViewParameter(ComputeShaderRHI, InputH0.GetBaseIndex(), ParamInputH0);
		RHICmdList.SetShaderResourceViewParameter(ComputeShaderRHI, InputOmega.GetBaseIndex(), ParamInputOmega);
	}

	void UnsetParameters(FRHICommandList &RHICmdList)
	{
		FComputeShaderRHIParamRef ComputeShaderRHI = GetComputeShader();
		FShaderResourceViewRHIParamRef NullSRV = FShaderResourceViewRHIParamRef();

		RHICmdList.SetShaderResourceViewParameter(ComputeShaderRHI, InputH0.GetBaseIndex(), NullSRV);
		RHICmdList.SetShaderResourceViewParameter(ComputeShaderRHI, InputOmega.GetBaseIndex(), NullSRV);
	}

	void SetOutput(FRHICommandList& RHICmdList, FUnorderedAccessViewRHIParamRef ParamOutputHtRW)
	{
		FComputeShaderRHIParamRef ComputeShaderRHI = GetComputeShader();
		if (OutputHtRW.IsBound())
		{
			RHICmdList.SetUAVParameter(ComputeShaderRHI, OutputHtRW.GetBaseIndex(), ParamOutputHtRW);
		}
	}

	void UnbindBuffers(FRHICommandList& RHICmdList)
	{
		FComputeShaderRHIParamRef ComputeShaderRHI = GetComputeShader();
		if (OutputHtRW.IsBound())
		{
			RHICmdList.SetUAVParameter(ComputeShaderRHI, OutputHtRW.GetBaseIndex(), FUnorderedAccessViewRHIParamRef());
		}
	}

	virtual bool Serialize(FArchive& Ar)
	{
		bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
		Ar << ActualDim << InWidth << OutWidth << OutHeight << DtxAddressOffset << DtyAddressOffset
			<< InputH0 << InputOmega << OutputHtRW;

		return bShaderHasOutdatedParameters;
	}

private:
	// Immutable
	FShaderParameter ActualDim;
	FShaderParameter InWidth;
	FShaderParameter OutWidth;
	FShaderParameter OutHeight;
	FShaderParameter DtxAddressOffset;
	FShaderParameter DtyAddressOffset;

	// Buffers
	FShaderResourceParameter InputH0;
	FShaderResourceParameter InputOmega;
	FShaderResourceParameter OutputHtRW;

};


//////////////////////////////////////////////////////////////////////////
// Radix008A_CS compute shader

BEGIN_UNIFORM_BUFFER_STRUCT(FRadixFFTUniformParameters, )
	DECLARE_UNIFORM_BUFFER_STRUCT_MEMBER(uint32, ThreadCount)
	DECLARE_UNIFORM_BUFFER_STRUCT_MEMBER(uint32, ostride)
	DECLARE_UNIFORM_BUFFER_STRUCT_MEMBER(uint32, istride)
	DECLARE_UNIFORM_BUFFER_STRUCT_MEMBER(uint32, pstride)
	DECLARE_UNIFORM_BUFFER_STRUCT_MEMBER(float, PhaseBase)
END_UNIFORM_BUFFER_STRUCT(FRadixFFTUniformParameters)

typedef TUniformBufferRef<FRadixFFTUniformParameters> FRadixFFTUniformBufferRef;

/**
 * FFT calculations for istride > 1 
 */
class FRadix008A_CS : public FGlobalShader
{
	DECLARE_SHADER_TYPE(FRadix008A_CS, Global)

public:
	static bool ShouldCache(EShaderPlatform Platform)
	{
		return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM5);
	}

	FRadix008A_CS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
		: FGlobalShader(Initializer)
	{
		SrcData.Bind(Initializer.ParameterMap, TEXT("g_SrcData"));
		DstData.Bind(Initializer.ParameterMap, TEXT("g_DstData"));
	}

	FRadix008A_CS()
	{
	}

	void SetParameters(FRHICommandList& RHICmdList, const FRadixFFTUniformBufferRef& UniformBuffer)
	{
		FComputeShaderRHIParamRef ComputeShaderRHI = GetComputeShader();

		SetUniformBufferParameter(RHICmdList, ComputeShaderRHI, GetUniformBufferParameter<FRadixFFTUniformParameters>(), UniformBuffer);
	}

	void SetParameters(FRHICommandList& RHICmdList, FShaderResourceViewRHIRef ParamSrcData, FUnorderedAccessViewRHIRef ParamDstData)
	{
		FComputeShaderRHIParamRef ComputeShaderRHI = GetComputeShader();

		RHICmdList.SetShaderResourceViewParameter(ComputeShaderRHI, SrcData.GetBaseIndex(), ParamSrcData);
		RHICmdList.SetUAVParameter(ComputeShaderRHI, DstData.GetBaseIndex(), ParamDstData);
	}

	void UnsetParameters(FRHICommandList& RHICmdList)
	{
		FComputeShaderRHIParamRef ComputeShaderRHI = GetComputeShader();

		RHICmdList.SetShaderResourceViewParameter(ComputeShaderRHI, SrcData.GetBaseIndex(), FShaderResourceViewRHIParamRef());
		RHICmdList.SetUAVParameter(ComputeShaderRHI, DstData.GetBaseIndex(), FUnorderedAccessViewRHIParamRef());
	}

	virtual bool Serialize(FArchive& Ar)
	{
		bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
		Ar << SrcData << DstData;

		return bShaderHasOutdatedParameters;
	}

private:
	// Buffers
	FShaderResourceParameter SrcData;
	FShaderResourceParameter DstData;

};

/**
 * pstride and istride parameters are excess here, but we use inheritance as its easier for now
 */
class FRadix008A_CS2 : public FRadix008A_CS
{
	DECLARE_SHADER_TYPE(FRadix008A_CS2, Global)

public:
	FRadix008A_CS2(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
		: FRadix008A_CS(Initializer)
	{
	}

	FRadix008A_CS2()
	{
	}
};


//////////////////////////////////////////////////////////////////////////
// Simple Quad vertex shader

/** The vertex data used to render displacement */
struct FQuadVertex
{
	FVector4 Position;
	FVector2D UV;
};

/** The displacement vertex declaration resource type */
class FQuadVertexDeclaration : public FRenderResource
{
public:
	FVertexDeclarationRHIRef VertexDeclarationRHI;

	/** Destructor */
	virtual ~FQuadVertexDeclaration() {}

	virtual void InitRHI()
	{
		FVertexDeclarationElementList Elements;
		Elements.Add(FVertexElement(0, STRUCT_OFFSET(FQuadVertex, Position), VET_Float4, 0, sizeof(FQuadVertex)));
		Elements.Add(FVertexElement(0, STRUCT_OFFSET(FQuadVertex, UV), VET_Float2, 1, sizeof(FQuadVertex)));
		VertexDeclarationRHI = RHICreateVertexDeclaration(Elements);
	}

	virtual void ReleaseRHI()
	{
		VertexDeclarationRHI.SafeRelease();
	}
};

class FQuadVS : public FGlobalShader
{
	DECLARE_SHADER_TYPE(FQuadVS, Global);

public:
	static bool ShouldCache(EShaderPlatform Platform)
	{
		return true;
	}

	FQuadVS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
		: FGlobalShader(Initializer)
	{
	}

	FQuadVS() {}
};


//////////////////////////////////////////////////////////////////////////
// Post-FFT data wrap up: Dx, Dy, Dz -> Displacement

BEGIN_UNIFORM_BUFFER_STRUCT(FUpdateDisplacementUniformParameters, )
	DECLARE_UNIFORM_BUFFER_STRUCT_MEMBER(float, ChoppyScale)
	DECLARE_UNIFORM_BUFFER_STRUCT_MEMBER(float, GridLen)
END_UNIFORM_BUFFER_STRUCT(FUpdateDisplacementUniformParameters)

typedef TUniformBufferRef<FUpdateDisplacementUniformParameters> FUpdateDisplacementUniformBufferRef;

/** Per frame parameters for UpdateDisplacementPS shader */
USTRUCT()
struct FUpdateDisplacementPSPerFrame
{
	GENERATED_USTRUCT_BODY()

	FVector4 m_pQuadVB[4];

	FShaderResourceViewRHIRef g_InputDxyz;

	// Used to pass params into render thread
	float g_ChoppyScale;
	float g_GridLen;
};

/**
 * Post-FFT data wrap up: Dx, Dy, Dz -> Displacement
 */
class FUpdateDisplacementPS : public FGlobalShader
{
	DECLARE_SHADER_TYPE(FUpdateDisplacementPS, Global)

public:
	static bool ShouldCache(EShaderPlatform Platform)
	{
		return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM5);
	}

	FUpdateDisplacementPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
		: FGlobalShader(Initializer)
	{
		ActualDim.Bind(Initializer.ParameterMap, TEXT("g_ActualDim"));
		InWidth.Bind(Initializer.ParameterMap, TEXT("g_InWidth"));
		OutWidth.Bind(Initializer.ParameterMap, TEXT("g_OutWidth"));
		OutHeight.Bind(Initializer.ParameterMap, TEXT("g_OutHeight"));
		DtxAddressOffset.Bind(Initializer.ParameterMap, TEXT("g_DtxAddressOffset"));
		DtyAddressOffset.Bind(Initializer.ParameterMap, TEXT("g_DtyAddressOffset"));

		InputDxyz.Bind(Initializer.ParameterMap, TEXT("g_InputDxyz"));
	}

	FUpdateDisplacementPS()
	{
	}

	void SetParameters(
		FRHICommandList& RHICmdList,
		uint32 ParamActualDim,
		uint32 ParamInWidth,
		uint32 ParamOutWidth,
		uint32 ParamOutHeight,
		uint32 ParamDtxAddressOffset,
		uint32 ParamDtyAddressOffset
		)
	{
		FPixelShaderRHIParamRef PixelShaderRHI = GetPixelShader();

		SetShaderValue(RHICmdList, PixelShaderRHI, ActualDim, ParamActualDim);
		SetShaderValue(RHICmdList, PixelShaderRHI, InWidth, ParamInWidth);
		SetShaderValue(RHICmdList, PixelShaderRHI, OutWidth, ParamOutWidth);
		SetShaderValue(RHICmdList, PixelShaderRHI, OutHeight, ParamOutHeight);
		SetShaderValue(RHICmdList, PixelShaderRHI, DtxAddressOffset, ParamDtxAddressOffset);
		SetShaderValue(RHICmdList, PixelShaderRHI, DtyAddressOffset, ParamDtyAddressOffset);
	}

	void SetParameters(
		FRHICommandList& RHICmdList,
		const FUpdateDisplacementUniformBufferRef& UniformBuffer,
		FShaderResourceViewRHIRef ParamInputDxyz
		)
	{
		FPixelShaderRHIParamRef PixelShaderRHI = GetPixelShader();

		SetUniformBufferParameter(RHICmdList, PixelShaderRHI, GetUniformBufferParameter<FUpdateDisplacementUniformParameters>(), UniformBuffer);

		RHICmdList.SetShaderResourceViewParameter(PixelShaderRHI, InputDxyz.GetBaseIndex(), ParamInputDxyz);
	}

	void UnsetParameters(FRHICommandList& RHICmdList)
	{
		FPixelShaderRHIParamRef PixelShaderRHI = GetPixelShader();

		RHICmdList.SetShaderResourceViewParameter(PixelShaderRHI, InputDxyz.GetBaseIndex(), FShaderResourceViewRHIParamRef());
	}

	virtual bool Serialize(FArchive& Ar)
	{
		bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
		Ar << ActualDim << InWidth << OutWidth << OutHeight << DtxAddressOffset << DtyAddressOffset << InputDxyz;

		return bShaderHasOutdatedParameters;
	}

private:
	// Immutable
	FShaderParameter ActualDim;
	FShaderParameter InWidth;
	FShaderParameter OutWidth;
	FShaderParameter OutHeight;
	FShaderParameter DtxAddressOffset;
	FShaderParameter DtyAddressOffset;

	// Buffers
	FShaderResourceParameter InputDxyz;

};


//////////////////////////////////////////////////////////////////////////
// Generate Normal

/** Per frame parameters for UpdateDisplacementPS shader */
USTRUCT()
struct FGenGradientFoldingPSPerFrame
{
	GENERATED_USTRUCT_BODY()

	FVector4 m_pQuadVB[4];

	// Used to pass params into render thread
	float g_ChoppyScale;
	float g_GridLen;
};

/**
 * Displacement -> Normal, Folding
 */
class FGenGradientFoldingPS : public FGlobalShader
{
	DECLARE_SHADER_TYPE(FGenGradientFoldingPS, Global)

public:
	static bool ShouldCache(EShaderPlatform Platform)
	{
		return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM5);
	}

	FGenGradientFoldingPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
		: FGlobalShader(Initializer)
	{
		ActualDim.Bind(Initializer.ParameterMap, TEXT("g_ActualDim"));
		InWidth.Bind(Initializer.ParameterMap, TEXT("g_InWidth"));
		OutWidth.Bind(Initializer.ParameterMap, TEXT("g_OutWidth"));
		OutHeight.Bind(Initializer.ParameterMap, TEXT("g_OutHeight"));
		DtxAddressOffset.Bind(Initializer.ParameterMap, TEXT("g_DtxAddressOffset"));
		DtyAddressOffset.Bind(Initializer.ParameterMap, TEXT("g_DtyAddressOffset"));

		DisplacementMap.Bind(Initializer.ParameterMap, TEXT("DisplacementMap"));
		DisplacementMapSampler.Bind(Initializer.ParameterMap, TEXT("DisplacementMapSampler"));
	}

	FGenGradientFoldingPS()
	{
	}

	void SetParameters(
		FRHICommandList& RHICmdList,
		uint32 ParamActualDim,
		uint32 ParamInWidth,
		uint32 ParamOutWidth,
		uint32 ParamOutHeight,
		uint32 ParamDtxAddressOffset,
		uint32 ParamDtyAddressOffset
		)
	{
		FPixelShaderRHIParamRef PixelShaderRHI = GetPixelShader();

		SetShaderValue(RHICmdList, PixelShaderRHI, ActualDim, ParamActualDim);
		SetShaderValue(RHICmdList, PixelShaderRHI, InWidth, ParamInWidth);
		SetShaderValue(RHICmdList, PixelShaderRHI, OutWidth, ParamOutWidth);
		SetShaderValue(RHICmdList, PixelShaderRHI, OutHeight, ParamOutHeight);
		SetShaderValue(RHICmdList, PixelShaderRHI, DtxAddressOffset, ParamDtxAddressOffset);
		SetShaderValue(RHICmdList, PixelShaderRHI, DtyAddressOffset, ParamDtyAddressOffset);
	}

	void SetParameters(
		FRHICommandList& RHICmdList,
		const FUpdateDisplacementUniformBufferRef& UniformBuffer,
		FTextureRHIParamRef DisplacementMapRHI
		)
	{
		FPixelShaderRHIParamRef PixelShaderRHI = GetPixelShader();

		SetUniformBufferParameter(RHICmdList, PixelShaderRHI, GetUniformBufferParameter<FUpdateDisplacementUniformParameters>(), UniformBuffer);

		FSamplerStateRHIParamRef SamplerStateLinear = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
		SetTextureParameter(RHICmdList, PixelShaderRHI, DisplacementMap, DisplacementMapSampler, SamplerStateLinear, DisplacementMapRHI);
	}

	void UnsetParameters(FRHICommandList& RHICmdList) {}

	virtual bool Serialize(FArchive& Ar)
	{
		bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
		Ar << ActualDim << InWidth << OutWidth << OutHeight << DtxAddressOffset << DtyAddressOffset
			<< DisplacementMap << DisplacementMapSampler;

		return bShaderHasOutdatedParameters;
	}

private:
	// Immutable
	FShaderParameter ActualDim;
	FShaderParameter InWidth;
	FShaderParameter OutWidth;
	FShaderParameter OutHeight;
	FShaderParameter DtxAddressOffset;
	FShaderParameter DtyAddressOffset;

	// Displacement map
	FShaderResourceParameter DisplacementMap;
	FShaderResourceParameter DisplacementMapSampler;

};



================================================
FILE: Source/VaOceanPlugin/Classes/VaOceanSimulator.h
================================================
// Copyright 2014-2016 Vladimir Alyamkin. All Rights Reserved.

#pragma once

#include "VaOceanTypes.h"
#include "VaOceanPluginPrivatePCH.h"

#include "VaOceanSimulator.generated.h"

#define PAD16(n) (((n)+15)/16*16)

/**
 * Renders normals and heightmap from Phillips spectrum
 */
UCLASS(Blueprintable, BlueprintType, ClassGroup=Environment)
class VAOCEANPLUGIN_API AVaOceanSimulator : public AActor
{
	GENERATED_UCLASS_BODY()


	//////////////////////////////////////////////////////////////////////////
	// Initialization

protected:
	/** Initialize all buffers and prepare shaders */
	void InitializeInternalData();

	/** Initialize the vector field */
	void InitHeightMap(const FSpectrumData& Params, TResourceArray<FVector2D>& out_h0, TResourceArray<float>& out_omega);

	/** Initialize buffers for shader */
	void CreateBufferAndUAV(FResourceArrayInterface* Data, uint32 byte_width, uint32 byte_stride, FStructuredBufferRHIRef* ppBuffer, FUnorderedAccessViewRHIRef* ppUAV, FShaderResourceViewRHIRef* ppSRV);

	/** Clear internal buffers and shader data */
	void ClearInternalData();

	/** Clear buffers and re-initalize them */
	void ResetInternalData();

	// Begin UObject Interface
	virtual void BeginDestroy() override;

#if WITH_EDITOR
	virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;
#endif // WITH_EDITOR
	// End UObject Interface

	/** Allow tick in editor */
	virtual bool ShouldTickIfViewportsOnly() const override;


	//////////////////////////////////////////////////////////////////////////
	// Simulation

public:
	/** Update ocean simulation */
	virtual void Tick(float DeltaSeconds) override;

protected:
	/** Update normals and heightmap from spectrum */
	void UpdateDisplacementMap(float WorldTime);


	//////////////////////////////////////////////////////////////////////////
	// Spectrum configuration

public:
	/** Get spectrum config */
	UFUNCTION(BlueprintCallable, Category = "VaOcean|FFT")
	const FSpectrumData& GetSpectrumConfig() const;

protected:
	/** Ocean spectrum data */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Config)
	FSpectrumData SpectrumConfig;


	//////////////////////////////////////////////////////////////////////////
	// Shader output targets

public:
	/** Render target for normal map that can be used by the editor */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Config)
	UTextureRenderTarget2D* DisplacementTexture;

	/** Render target for height map that can be used by the editor */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Config)
	UTextureRenderTarget2D* GradientTexture;


	//////////////////////////////////////////////////////////////////////////
	// Parameters that will be send to rendering thread

protected:
	FUpdateSpectrumCSImmutable UpdateSpectrumCSImmutableParams;


	//////////////////////////////////////////////////////////////////////////
	// Spectrum simulation data

protected:
	/** Initial height field H(0) generated by Phillips spectrum & Gauss distribution. */
	FStructuredBufferRHIRef m_pBuffer_Float2_H0;
	FUnorderedAccessViewRHIRef m_pUAV_H0;
	FShaderResourceViewRHIRef m_pSRV_H0;

	/** Angular frequency */
	FStructuredBufferRHIRef m_pBuffer_Float_Omega;
	FUnorderedAccessViewRHIRef m_pUAV_Omega;
	FShaderResourceViewRHIRef m_pSRV_Omega;

	/** Height field H(t), choppy field Dx(t) and Dy(t) in frequency domain, updated each frame. */
	FStructuredBufferRHIRef m_pBuffer_Float2_Ht;
	FUnorderedAccessViewRHIRef m_pUAV_Ht;
	FShaderResourceViewRHIRef m_pSRV_Ht;

	/** Height & choppy buffer in the space domain, corresponding to H(t), Dx(t) and Dy(t) */
	FStructuredBufferRHIRef m_pBuffer_Float_Dxyz;
	FUnorderedAccessViewRHIRef m_pUAV_Dxyz;
	FShaderResourceViewRHIRef m_pSRV_Dxyz;

	FVector4 m_pQuadVB[4];

	/** FFT wrap-up */
	FRadixPlan512 FFTPlan;

	/** Initialization flags */
	bool bSimulatorInitializated;

	/** Internal world simulation time */
	float SimulationWorldTime;


	//////////////////////////////////////////////////////////////////////////
	// Utilities

public:
	/**
	 * Creates a new RenderTarget with desired params
	 *
	 * @param bInForceLinearGamma	Whether or not to force linear gamma
	 * @param InPixelFormat			Pixel format of the render target
	 * @param InTargetSize			Dimensions of the render target
	 * @return						Created render target
	 */
	UTextureRenderTarget2D* CreateRenderTarget(bool bInForceLinearGamma, bool bNormalMap, EPixelFormat InPixelFormat, FIntPoint& InTargetSize);

	/**
	 * SetupsRenderTarget with desired params
	 *
	 * @param bInForceLinearGamma	Whether or not to force linear gamma
	 * @param InPixelFormat			Pixel format of the render target
	 * @param InTargetSize			Dimensions of the render target
	 * @return						Created render target
	 */
	static void SetupRenderTarget(UTextureRenderTarget2D* InRenderTarget, bool bInForceLinearGamma, bool bNormalMap, EPixelFormat InPixelFormat, FIntPoint& InTargetSize);

};


================================================
FILE: Source/VaOceanPlugin/Classes/VaOceanTypes.h
================================================
// Copyright 2014 Vladimir Alyamkin. All Rights Reserved.

#pragma once

#include "VaOceanTypes.generated.h"

/** Phillips spectrum configuration */
USTRUCT(BlueprintType)
struct FSpectrumData
{
	GENERATED_USTRUCT_BODY()

	/** The size of displacement map. Must be power of 2.
	 * Not editable because of FFT shader config */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
	int32 DispMapDimension;

	/** The side length (world space) of square patch. Typical value is 1000 ~ 2000. */
	UPROPERTY(EditAnywhere)
	float PatchLength;

	/** Adjust the time interval for simulation (controls the simulation speed) */
	UPROPERTY(EditAnywhere)
	float TimeScale;

	/** Amplitude for transverse wave. Around 1.0 (not the world space height). */
	UPROPERTY(EditAnywhere)
	float WaveAmplitude;

	/** Wind direction. Normalization not required */
	UPROPERTY(EditAnywhere)
	FVector2D WindDirection;

	/** The bigger the wind speed, the larger scale of wave crest. But the wave scale can be no larger than PatchLength. Around 100 ~ 1000 */
	UPROPERTY(EditAnywhere)
	float WindSpeed;

	/** This value damps out the waves against the wind direction. Smaller value means higher wind dependency. */
	UPROPERTY(EditAnywhere)
	float WindDependency;

	/** The amplitude for longitudinal wave. Higher value creates pointy crests. Must be positive. */
	UPROPERTY(EditAnywhere)
	float ChoppyScale;

	/** Defaults */
	FSpectrumData()
	{
		DispMapDimension = 512;
		PatchLength = 2000.0f;
		TimeScale = 0.8f;
		WaveAmplitude = 0.35f;
		WindDirection = FVector2D(0.8f, 0.6f);
		WindSpeed = 600.0f;
		WindDependency = 0.07f;
		ChoppyScale = 1.3f;
	}
};


================================================
FILE: Source/VaOceanPlugin/Private/VaOceanPlugin.cpp
================================================
// Copyright 2014 Vladimir Alyamkin. All Rights Reserved.

#include "VaOceanPluginPrivatePCH.h"

class FVaOceanPlugin : public IVaOceanPlugin
{
	/** IModuleInterface implementation */
	virtual void StartupModule() override
	{

	}

	virtual void ShutdownModule() override
	{

	}
};

IMPLEMENT_MODULE( FVaOceanPlugin, VaOceanPlugin )

DEFINE_LOG_CATEGORY(LogVaOcean);


================================================
FILE: Source/VaOceanPlugin/Private/VaOceanPluginPrivatePCH.h
================================================
// Copyright 2014-2016 Vladimir Alyamkin. All Rights Reserved.

#pragma once

#include "CoreUObject.h"
#include "Engine.h"
#include "UniformBuffer.h"
#include "ShaderParameters.h"
#include "ShaderParameterUtils.h"
#include "GlobalShader.h"
#include "RHIStaticStates.h"

// You should place include statements to your module's private header files here.  You only need to
// add includes for headers that are used in most of your module's source files though.
#include "ModuleManager.h"

DECLARE_LOG_CATEGORY_EXTERN(LogVaOcean, Log, All);

#include "IVaOceanPlugin.h"

#include "VaOceanTypes.h"
#include "VaOceanShaders.h"
#include "VaOceanRadixFFT.h"
#include "VaOceanSimulator.h"


================================================
FILE: Source/VaOceanPlugin/Private/VaOceanRadixFFT.cpp
================================================
// Copyright 2014-2016 Vladimir Alyamkin. All Rights Reserved.

#include "VaOceanPluginPrivatePCH.h"

void Radix008A(
	FRHICommandListImmediate & RHICmdList,
	FRadixPlan512* Plan,
	uint32 ParamSet,
	FUnorderedAccessViewRHIRef pUAV_Dst,
	FShaderResourceViewRHIRef pSRV_Src,
	uint32 ThreadCount,
	uint32 istride)
{
	check(ParamSet < FFT_PARAM_SETS);
	const auto FeatureLevel = GMaxRHIFeatureLevel;
	// Setup execution configuration
	uint32 grid = ThreadCount / COHERENCY_GRANULARITY;

	FRadixFFTUniformParameters Parameters;
	Parameters.ThreadCount = Plan->PerFrame[ParamSet].ThreadCount;
	Parameters.ostride = Plan->PerFrame[ParamSet].ostride;
	Parameters.istride = Plan->PerFrame[ParamSet].istride;
	Parameters.pstride = Plan->PerFrame[ParamSet].pstride;
	Parameters.PhaseBase = Plan->PerFrame[ParamSet].PhaseBase;

	FRadixFFTUniformBufferRef UniformBuffer =
		FRadixFFTUniformBufferRef::CreateUniformBufferImmediate(Parameters, EUniformBufferUsage::UniformBuffer_SingleFrame);

	if (istride > 1)
	{
		TShaderMapRef<FRadix008A_CS> Radix008A_CS(GetGlobalShaderMap(FeatureLevel));
		RHICmdList.SetComputeShader(Radix008A_CS->GetComputeShader());

		Radix008A_CS->SetParameters(RHICmdList, UniformBuffer);
		Radix008A_CS->SetParameters(RHICmdList, pSRV_Src, pUAV_Dst);

		RHICmdList.DispatchComputeShader(grid, 1, 1);

		Radix008A_CS->UnsetParameters(RHICmdList);
	}
	else
	{
		TShaderMapRef<FRadix008A_CS2> Radix008A_CS2(GetGlobalShaderMap(FeatureLevel));
		RHICmdList.SetComputeShader(Radix008A_CS2->GetComputeShader());

		Radix008A_CS2->SetParameters(RHICmdList, UniformBuffer);
		Radix008A_CS2->SetParameters(RHICmdList, pSRV_Src, pUAV_Dst);

		RHICmdList.DispatchComputeShader(grid, 1, 1);

		Radix008A_CS2->UnsetParameters(RHICmdList);
	}
}

void RadixSetPerFrameParams(FRadixPlan512* Plan,
	uint32 ParamSet,
	uint32 ThreadCount,
	uint32 ostride,
	uint32 istride,
	uint32 pstride,
	float PhaseBase)
{
	check(ParamSet < FFT_PARAM_SETS);

	Plan->PerFrame[ParamSet].ThreadCount = ThreadCount;
	Plan->PerFrame[ParamSet].ostride = ostride;
	Plan->PerFrame[ParamSet].istride = istride;
	Plan->PerFrame[ParamSet].pstride = pstride;
	Plan->PerFrame[ParamSet].PhaseBase = PhaseBase;
}

void RadixCreatePlan(FRadixPlan512* Plan, uint32 Slices)
{
	Plan->Slices = Slices;

	// Create 6 param sets for 512x512 transform
	const uint32 thread_count = Plan->Slices * (512 * 512) / 8;
	uint32 ostride = 512 * 512 / 8;
	uint32 istride = ostride;
	uint32 pstride = 512;
	double phase_base = -TWO_PI / (512.0 * 512.0);

	RadixSetPerFrameParams(Plan, 0, thread_count, ostride, istride, pstride, (float)phase_base);

	for (int i = 1; i < FFT_PARAM_SETS; i++)
	{
		istride /= 8;
		phase_base *= 8.0;

		if (i == 3)
		{
			ostride /= 512;
			pstride = 1;
		}

		RadixSetPerFrameParams(Plan, i, thread_count, ostride, istride, pstride, (float)phase_base);
	}
	
	// Temp buffers
	uint32 BytesPerElement = sizeof(float) * 2;
	uint32 NumElements = (512 * Plan->Slices) * 512;

	FRHIResourceCreateInfo ResourceCreateInfo;
	ResourceCreateInfo.BulkData = nullptr;
	ResourceCreateInfo.ResourceArray = nullptr;
	Plan->pBuffer_Tmp = RHICreateStructuredBuffer(BytesPerElement, BytesPerElement * NumElements, (BUF_UnorderedAccess | BUF_ShaderResource), ResourceCreateInfo);

	Plan->pUAV_Tmp = RHICreateUnorderedAccessView(Plan->pBuffer_Tmp, false, false);
	Plan->pSRV_Tmp = RHICreateShaderResourceView(Plan->pBuffer_Tmp);
}

void RadixDestroyPlan(FRadixPlan512* Plan)
{
	Plan->pBuffer_Tmp.SafeRelease();
	Plan->pUAV_Tmp.SafeRelease();
	Plan->pSRV_Tmp.SafeRelease();
}

void RadixCompute(
	FRHICommandListImmediate& RHICmdList,
	FRadixPlan512* Plan,
	FUnorderedAccessViewRHIRef pUAV_Dst,
	FShaderResourceViewRHIRef pSRV_Dst,
	FShaderResourceViewRHIRef pSRV_Src)
{
	const uint32 thread_count = Plan->Slices * (512 * 512) / 8;
	uint32 istride = 512 * 512;

	FUnorderedAccessViewRHIRef pUAV_Tmp = Plan->pUAV_Tmp;
	FShaderResourceViewRHIRef pSRV_Tmp = Plan->pSRV_Tmp;

	istride /= 8;
	Radix008A(RHICmdList, Plan, 0, pUAV_Tmp, pSRV_Src, thread_count, istride);

	istride /= 8;
	Radix008A(RHICmdList, Plan, 1, pUAV_Dst, pSRV_Tmp, thread_count, istride);

	istride /= 8;
	Radix008A(RHICmdList, Plan, 2, pUAV_Tmp, pSRV_Dst, thread_count, istride);

	istride /= 8;
	Radix008A(RHICmdList, Plan, 3, pUAV_Dst, pSRV_Tmp, thread_count, istride);

	istride /= 8;
	Radix008A(RHICmdList, Plan, 4, pUAV_Tmp, pSRV_Dst, thread_count, istride);

	istride /= 8;
	Radix008A(RHICmdList, Plan, 5, pUAV_Dst, pSRV_Tmp, thread_count, istride);
}


================================================
FILE: Source/VaOceanPlugin/Private/VaOceanShaders.cpp
================================================
// Copyright 2014-2016 Vladimir Alyamkin. All Rights Reserved.

#include "VaOceanPluginPrivatePCH.h"

IMPLEMENT_SHADER_TYPE(, FUpdateSpectrumCS, TEXT("VaOcean_CS"), TEXT("UpdateSpectrumCS"), SF_Compute);
IMPLEMENT_SHADER_TYPE(, FRadix008A_CS, TEXT("VaOcean_FFT"), TEXT("Radix008A_CS"), SF_Compute);
IMPLEMENT_SHADER_TYPE(, FRadix008A_CS2, TEXT("VaOcean_FFT"), TEXT("Radix008A_CS2"), SF_Compute);

IMPLEMENT_SHADER_TYPE(, FQuadVS, TEXT("VaOcean_VS_PS"), TEXT("QuadVS"), SF_Vertex);
IMPLEMENT_SHADER_TYPE(, FUpdateDisplacementPS, TEXT("VaOcean_VS_PS"), TEXT("UpdateDisplacementPS"), SF_Pixel);
IMPLEMENT_SHADER_TYPE(, FGenGradientFoldingPS, TEXT("VaOcean_VS_PS"), TEXT("GenGradientFoldingPS"), SF_Pixel);

IMPLEMENT_UNIFORM_BUFFER_STRUCT(FUpdateSpectrumUniformParameters, TEXT("PerFrameSp"));
IMPLEMENT_UNIFORM_BUFFER_STRUCT(FUpdateDisplacementUniformParameters, TEXT("PerFrameDisp"));
IMPLEMENT_UNIFORM_BUFFER_STRUCT(FRadixFFTUniformParameters, TEXT("PerFrameFFT"));


================================================
FILE: Source/VaOceanPlugin/Private/VaOceanSimulator.cpp
================================================
// Copyright 2014-2016 Vladimir Alyamkin. All Rights Reserved.

#include "VaOceanPluginPrivatePCH.h"

#define HALF_SQRT_2	0.7071068f
#define GRAV_ACCEL	981.0f	// The acceleration of gravity, cm/s^2

#define BLOCK_SIZE_X 16
#define BLOCK_SIZE_Y 16

/** Vertex declaration for the fullscreen 2D quad */
TGlobalResource<FQuadVertexDeclaration> GQuadVertexDeclaration;


//////////////////////////////////////////////////////////////////////////
// Height map generation helpers

/** Generating gaussian random number with mean 0 and standard deviation 1 */
float Gauss()
{
	float u1 = rand() / (float)RAND_MAX;
	float u2 = rand() / (float)RAND_MAX;

	if (u1 < 1e-6f)
	{
		u1 = 1e-6f;
	}

	return sqrtf(-2 * logf(u1)) * cosf(2 * PI * u2);
}

/**
 * Phillips Spectrum
 * K: normalized wave vector, W: wind direction, v: wind velocity, a: amplitude constant
 */
float Phillips(FVector2D K, FVector2D W, float v, float a, float dir_depend)
{
	// Largest possible wave from constant wind of velocity v
	float l = v * v / GRAV_ACCEL;

	// Damp out waves with very small length w << l
	float w = l / 1000;

	float Ksqr = K.X * K.X + K.Y * K.Y;
	float Kcos = K.X * W.X + K.Y * W.Y;
	float phillips = a * expf(-1 / (l * l * Ksqr)) / (Ksqr * Ksqr * Ksqr) * (Kcos * Kcos);

	// Filter out waves moving opposite to wind
	if (Kcos < 0)
	{
		phillips *= dir_depend;
	}

	// Damp out waves with very small length w << l
	return phillips * expf(-Ksqr * w * w);
}


//////////////////////////////////////////////////////////////////////////
// Phillips spectrum simulator

AVaOceanSimulator::AVaOceanSimulator(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
	PrimaryActorTick.bCanEverTick = true;
	PrimaryActorTick.TickGroup = TG_DuringPhysics;
	bReplicates = true;
	NetUpdateFrequency = 10.f;

	SimulationWorldTime = 0.f;

	// Vertex to draw on render targets
	m_pQuadVB[0].Set(-1.0f, -1.0f, 0.0f, 1.0f);
	m_pQuadVB[1].Set(-1.0f,  1.0f, 0.0f, 1.0f);
	m_pQuadVB[2].Set( 1.0f, -1.0f, 0.0f, 1.0f);
	m_pQuadVB[3].Set( 1.0f,  1.0f, 0.0f, 1.0f);
}

void AVaOceanSimulator::InitializeInternalData()
{
	// Cache shader immutable parameters (looks ugly, but nicely used then)
	UpdateSpectrumCSImmutableParams.g_ActualDim = SpectrumConfig.DispMapDimension;
	UpdateSpectrumCSImmutableParams.g_InWidth = UpdateSpectrumCSImmutableParams.g_ActualDim + 4;
	UpdateSpectrumCSImmutableParams.g_OutWidth = UpdateSpectrumCSImmutableParams.g_ActualDim;
	UpdateSpectrumCSImmutableParams.g_OutHeight = UpdateSpectrumCSImmutableParams.g_ActualDim;
	UpdateSpectrumCSImmutableParams.g_DtxAddressOffset = FMath::Square(UpdateSpectrumCSImmutableParams.g_ActualDim);
	UpdateSpectrumCSImmutableParams.g_DtyAddressOffset = FMath::Square(UpdateSpectrumCSImmutableParams.g_ActualDim) * 2;

	// Height map H(0)
	int32 height_map_size = (SpectrumConfig.DispMapDimension + 4) * (SpectrumConfig.DispMapDimension + 1);
	TResourceArray<FVector2D> h0_data;
	h0_data.Init(FVector2D::ZeroVector, height_map_size);
	TResourceArray<float> omega_data;
	omega_data.Init(0.0f, height_map_size);
	InitHeightMap(SpectrumConfig, h0_data, omega_data);

	int hmap_dim = SpectrumConfig.DispMapDimension;
	int input_full_size = (hmap_dim + 4) * (hmap_dim + 1);
	// This value should be (hmap_dim / 2 + 1) * hmap_dim, but we use full sized buffer here for simplicity.
	int input_half_size = hmap_dim * hmap_dim;
	int output_size = hmap_dim * hmap_dim;

	// For filling the buffer with zeroes
	TResourceArray<float> zero_data;
	zero_data.Init(0.0f, 3 * output_size * 2);

	// RW buffer allocations
	// H0
	uint32 float2_stride = 2 * sizeof(float);
	CreateBufferAndUAV(&h0_data, input_full_size * float2_stride, float2_stride, &m_pBuffer_Float2_H0, &m_pUAV_H0, &m_pSRV_H0);

	// Notice: The following 3 buffers should be half sized buffer because of conjugate symmetric input. But
	// we use full sized buffers due to the CS4.0 restriction.

	// Put H(t), Dx(t) and Dy(t) into one buffer because CS4.0 allows only 1 UAV at a time
	CreateBufferAndUAV(&zero_data, 3 * input_half_size * float2_stride, float2_stride, &m_pBuffer_Float2_Ht, &m_pUAV_Ht, &m_pSRV_Ht);

	// omega
	CreateBufferAndUAV(&omega_data, input_full_size * sizeof(float), sizeof(float), &m_pBuffer_Float_Omega, &m_pUAV_Omega, &m_pSRV_Omega);

	// Re-init the array because it was discarded by previous buffer creation
	zero_data.Empty();
	zero_data.Init(0.0f, 3 * output_size * 2);
	// Notice: The following 3 should be real number data. But here we use the complex numbers and C2C FFT
	// due to the CS4.0 restriction.
	// Put Dz, Dx and Dy into one buffer because CS4.0 allows only 1 UAV at a time
	CreateBufferAndUAV(&zero_data, 3 * output_size * float2_stride, float2_stride, &m_pBuffer_Float_Dxyz, &m_pUAV_Dxyz, &m_pSRV_Dxyz);

	// FFT
	RadixCreatePlan(&FFTPlan, 3); 

	// Turn the flag on
	bSimulatorInitializated = true;
}

void AVaOceanSimulator::InitHeightMap(const FSpectrumData& Params, TResourceArray<FVector2D>& out_h0, TResourceArray<float>& out_omega)
{
	int32 i, j;
	FVector2D K, Kn;

	FVector2D wind_dir = Params.WindDirection;
	wind_dir.Normalize();

	float a = Params.WaveAmplitude * 1e-7f;	// It is too small. We must scale it for editing.
	float v = Params.WindSpeed;
	float dir_depend = Params.WindDependency;

	int height_map_dim = Params.DispMapDimension;
	float patch_length = Params.PatchLength;

	// Initialize random generator.
	srand(0);

	for (i = 0; i <= height_map_dim; i++)
	{
		// K is wave-vector, range [-|DX/W, |DX/W], [-|DY/H, |DY/H]
		K.Y = (-height_map_dim / 2.0f + i) * (2 * PI / patch_length);

		for (j = 0; j <= height_map_dim; j++)
		{
			K.X = (-height_map_dim / 2.0f + j) * (2 * PI / patch_length);

			float phil = (K.X == 0 && K.Y == 0) ? 0 : sqrtf(Phillips(K, wind_dir, v, a, dir_depend));

			out_h0[i * (height_map_dim + 4) + j].X = float(phil * Gauss() * HALF_SQRT_2);
			out_h0[i * (height_map_dim + 4) + j].Y = float(phil * Gauss() * HALF_SQRT_2);

			// The angular frequency is following the dispersion relation:
			//            out_omega^2 = g*k
			// The equation of Gerstner wave:
			//            x = x0 - K/k * A * sin(dot(K, x0) - sqrt(g * k) * t), x is a 2D vector.
			//            z = A * cos(dot(K, x0) - sqrt(g * k) * t)
			// Gerstner wave shows that a point on a simple sinusoid wave is doing a uniform circular
			// motion with the center (x0, y0, z0), radius A, and the circular plane is parallel to
			// vector K.
			out_omega[i * (height_map_dim + 4) + j] = sqrtf(GRAV_ACCEL * sqrtf(K.X * K.X + K.Y * K.Y));
		}
	}
}

void AVaOceanSimulator::CreateBufferAndUAV(FResourceArrayInterface* Data, uint32 byte_width, uint32 byte_stride,
	FStructuredBufferRHIRef* ppBuffer, FUnorderedAccessViewRHIRef* ppUAV, FShaderResourceViewRHIRef* ppSRV)
{
	FRHIResourceCreateInfo ResourceCreateInfo;
	ResourceCreateInfo.ResourceArray = Data;
	*ppBuffer = RHICreateStructuredBuffer(byte_stride, Data->GetResourceDataSize(), (BUF_UnorderedAccess | BUF_ShaderResource), ResourceCreateInfo);

	*ppUAV = RHICreateUnorderedAccessView(*ppBuffer, false, false);
	*ppSRV = RHICreateShaderResourceView(*ppBuffer);
}

void AVaOceanSimulator::ClearInternalData()
{
	RadixDestroyPlan(&FFTPlan);

	m_pBuffer_Float2_H0.SafeRelease();
	m_pUAV_H0.SafeRelease();
	m_pSRV_H0.SafeRelease();

	m_pBuffer_Float_Omega.SafeRelease();
	m_pUAV_Omega.SafeRelease();
	m_pSRV_Omega.SafeRelease();

	m_pBuffer_Float2_Ht.SafeRelease();
	m_pUAV_Ht.SafeRelease();
	m_pSRV_Ht.SafeRelease();

	m_pBuffer_Float_Dxyz.SafeRelease();
	m_pUAV_Dxyz;
	m_pSRV_Dxyz;

	bSimulatorInitializated = false;
}

void AVaOceanSimulator::ResetInternalData()
{
	ClearInternalData();
	InitializeInternalData();
}

void AVaOceanSimulator::BeginDestroy()
{
	ClearInternalData();

	Super::BeginDestroy();
}


//////////////////////////////////////////////////////////////////////////
// Simulation

#if WITH_EDITOR
void AVaOceanSimulator::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
{
	// AActor::PostEditChange will ForceUpdateComponents()
	Super::PostEditChangeProperty(PropertyChangedEvent);

	// @todo Update shader configuration
}
#endif // WITH_EDITOR

bool AVaOceanSimulator::ShouldTickIfViewportsOnly() const
{
	return true;
}

void AVaOceanSimulator::Tick(float DeltaSeconds)
{
	Super::Tick(DeltaSeconds);

	// Check that data is initializated
	if (!bSimulatorInitializated)
	{
		InitializeInternalData();
	}

	// Tick world time
	SimulationWorldTime += DeltaSeconds;

	// Process simulation shaders
	UpdateDisplacementMap(SimulationWorldTime);
}

void AVaOceanSimulator::UpdateDisplacementMap(float WorldTime)
{
	if (!DisplacementTexture || !GradientTexture)
		return;

	// ---------------------------- H(0) -> H(t), D(x, t), D(y, t) --------------------------------
	FUpdateSpectrumCSPerFrame UpdateSpectrumCSPerFrameParams;
	UpdateSpectrumCSPerFrameParams.g_Time = WorldTime * SpectrumConfig.TimeScale;
	UpdateSpectrumCSPerFrameParams.g_ChoppyScale = SpectrumConfig.ChoppyScale;
	UpdateSpectrumCSPerFrameParams.m_pSRV_H0 = m_pSRV_H0;
	UpdateSpectrumCSPerFrameParams.m_pSRV_Omega = m_pSRV_Omega;
	UpdateSpectrumCSPerFrameParams.m_pUAV_Ht = m_pUAV_Ht;

	ENQUEUE_UNIQUE_RENDER_COMMAND_TWOPARAMETER(
		UpdateSpectrumCSCommand,
		FUpdateSpectrumCSImmutable, ImmutableParams, UpdateSpectrumCSImmutableParams,
		FUpdateSpectrumCSPerFrame, PerFrameParams, UpdateSpectrumCSPerFrameParams,
		{
			FUpdateSpectrumUniformParameters Parameters;
			const auto FeatureLevel = GMaxRHIFeatureLevel;
			Parameters.Time = PerFrameParams.g_Time;

			FUpdateSpectrumUniformBufferRef UniformBuffer = 
				FUpdateSpectrumUniformBufferRef::CreateUniformBufferImmediate(Parameters, UniformBuffer_SingleFrame);

			TShaderMapRef<FUpdateSpectrumCS> UpdateSpectrumCS(GetGlobalShaderMap(GMaxRHIFeatureLevel));
			RHICmdList.SetComputeShader(UpdateSpectrumCS->GetComputeShader());

			UpdateSpectrumCS->SetParameters(RHICmdList, ImmutableParams.g_ActualDim,
				ImmutableParams.g_InWidth, ImmutableParams.g_OutWidth, ImmutableParams.g_OutHeight,
				ImmutableParams.g_DtxAddressOffset, ImmutableParams.g_DtyAddressOffset);

			UpdateSpectrumCS->SetParameters(RHICmdList, UniformBuffer, PerFrameParams.m_pSRV_H0, PerFrameParams.m_pSRV_Omega);
			UpdateSpectrumCS->SetOutput(RHICmdList, PerFrameParams.m_pUAV_Ht);

			uint32 group_count_x = (ImmutableParams.g_ActualDim + BLOCK_SIZE_X - 1) / BLOCK_SIZE_X;
			uint32 group_count_y = (ImmutableParams.g_ActualDim + BLOCK_SIZE_Y - 1) / BLOCK_SIZE_Y;
			RHICmdList.DispatchComputeShader(group_count_x, group_count_y, 1);

			UpdateSpectrumCS->UnsetParameters(RHICmdList);
			UpdateSpectrumCS->UnbindBuffers(RHICmdList);
		});

	// ------------------------------------ Perform FFT -------------------------------------------
	ENQUEUE_UNIQUE_RENDER_COMMAND_FOURPARAMETER(
		RadixFFTCommand,
		FRadixPlan512*, pPlan, &FFTPlan,
		FUnorderedAccessViewRHIRef, m_pUAV_Dxyz, m_pUAV_Dxyz,
		FShaderResourceViewRHIRef, m_pSRV_Dxyz, m_pSRV_Dxyz,
		FShaderResourceViewRHIRef, m_pSRV_Ht, m_pSRV_Ht,
		{
			RadixCompute(RHICmdList, pPlan, m_pUAV_Dxyz, m_pSRV_Dxyz, m_pSRV_Ht);
		});

	// --------------------------------- Wrap Dx, Dy and Dz ---------------------------------------
	FUpdateDisplacementPSPerFrame UpdateDisplacementPSPerFrameParams;
	UpdateDisplacementPSPerFrameParams.g_ChoppyScale = SpectrumConfig.ChoppyScale;
	UpdateDisplacementPSPerFrameParams.g_GridLen = SpectrumConfig.DispMapDimension / SpectrumConfig.PatchLength;
	UpdateDisplacementPSPerFrameParams.g_InputDxyz = m_pSRV_Dxyz;
	FMemory::Memcpy(UpdateDisplacementPSPerFrameParams.m_pQuadVB, m_pQuadVB, sizeof(m_pQuadVB[0]) * 4);

	FTextureRenderTargetResource* DisplacementRenderTarget = DisplacementTexture->GameThread_GetRenderTargetResource();

	ENQUEUE_UNIQUE_RENDER_COMMAND_THREEPARAMETER(
		UpdateDisplacementPSCommand,
		FTextureRenderTargetResource*, TextureRenderTarget, DisplacementRenderTarget,
		FUpdateSpectrumCSImmutable, ImmutableParams, UpdateSpectrumCSImmutableParams,		// We're using the same params as for CS
		FUpdateDisplacementPSPerFrame, PerFrameParams, UpdateDisplacementPSPerFrameParams,
		{
			const auto FeatureLevel = GMaxRHIFeatureLevel;
			FUpdateDisplacementUniformParameters Parameters;
			Parameters.ChoppyScale = PerFrameParams.g_ChoppyScale;
			Parameters.GridLen = PerFrameParams.g_GridLen;

			FUpdateDisplacementUniformBufferRef UniformBuffer =
				FUpdateDisplacementUniformBufferRef::CreateUniformBufferImmediate(Parameters, UniformBuffer_SingleFrame);

			SetRenderTarget(RHICmdList, TextureRenderTarget->GetRenderTargetTexture(), NULL);
			RHICmdList.Clear(true, FLinearColor::Transparent, false, 0.f, false, 0, FIntRect());
			
			// Be sure we're blending right without any alpha influence on Color blending
			RHICmdList.SetBlendState(TStaticBlendState<>::GetRHI());

			TShaderMapRef<FQuadVS> QuadVS(GetGlobalShaderMap(GMaxRHIFeatureLevel));
			TShaderMapRef<FUpdateDisplacementPS> UpdateDisplacementPS(GetGlobalShaderMap(GMaxRHIFeatureLevel));

			static FGlobalBoundShaderState UpdateDisplacementBoundShaderState;
			SetGlobalBoundShaderState(RHICmdList, GMaxRHIFeatureLevel, UpdateDisplacementBoundShaderState, GQuadVertexDeclaration.VertexDeclarationRHI, *QuadVS, *UpdateDisplacementPS);

			UpdateDisplacementPS->SetParameters(RHICmdList, ImmutableParams.g_ActualDim,
				ImmutableParams.g_InWidth, ImmutableParams.g_OutWidth, ImmutableParams.g_OutHeight,
				ImmutableParams.g_DtxAddressOffset, ImmutableParams.g_DtyAddressOffset);

			UpdateDisplacementPS->SetParameters(RHICmdList, UniformBuffer, PerFrameParams.g_InputDxyz);

			DrawPrimitiveUP(RHICmdList, PT_TriangleStrip, 2, PerFrameParams.m_pQuadVB, sizeof(PerFrameParams.m_pQuadVB[0]));

			UpdateDisplacementPS->UnsetParameters(RHICmdList);
		});

	// ----------------------------------- Generate Normal ----------------------------------------
	FGenGradientFoldingPSPerFrame GenGradientFoldingPSPerFrameParams;
	GenGradientFoldingPSPerFrameParams.g_ChoppyScale = SpectrumConfig.ChoppyScale;
	GenGradientFoldingPSPerFrameParams.g_GridLen = SpectrumConfig.DispMapDimension / SpectrumConfig.PatchLength;
	FMemory::Memcpy(GenGradientFoldingPSPerFrameParams.m_pQuadVB, m_pQuadVB, sizeof(m_pQuadVB[0]) * 4);

	FTextureRenderTargetResource* GradientRenderTarget = GradientTexture->GameThread_GetRenderTargetResource();

	ENQUEUE_UNIQUE_RENDER_COMMAND_FOURPARAMETER(
		GenGradientFoldingPSCommand,
		FTextureRenderTargetResource*, TextureRenderTarget, GradientRenderTarget,
		FUpdateSpectrumCSImmutable, ImmutableParams, UpdateSpectrumCSImmutableParams,		// We're using the same params as for CS
		FGenGradientFoldingPSPerFrame, PerFrameParams, GenGradientFoldingPSPerFrameParams,
		FTextureRenderTargetResource*, DisplacementRenderTarget, DisplacementRenderTarget,
		{
			FUpdateDisplacementUniformParameters Parameters;
			const auto FeatureLevel = GMaxRHIFeatureLevel;
			Parameters.ChoppyScale = PerFrameParams.g_ChoppyScale;
			Parameters.GridLen = PerFrameParams.g_GridLen;

			FUpdateDisplacementUniformBufferRef UniformBuffer = FUpdateDisplacementUniformBufferRef::CreateUniformBufferImmediate(Parameters, UniformBuffer_SingleFrame);

			SetRenderTarget(RHICmdList, TextureRenderTarget->GetRenderTargetTexture(), FTextureRHIRef());
			RHICmdList.Clear(true, FLinearColor::Transparent, false, 0.f, false, 0, FIntRect());

			// Be sure we're blending right without any alpha influence on Color blending
			RHICmdList.SetBlendState(TStaticBlendState<>::GetRHI());

			TShaderMapRef<FQuadVS> QuadVS(GetGlobalShaderMap(GMaxRHIFeatureLevel));
			TShaderMapRef<FGenGradientFoldingPS> GenGradientFoldingPS(GetGlobalShaderMap(GMaxRHIFeatureLevel));

			static FGlobalBoundShaderState UpdateDisplacementBoundShaderState;
			SetGlobalBoundShaderState(RHICmdList, GMaxRHIFeatureLevel, UpdateDisplacementBoundShaderState, GQuadVertexDeclaration.VertexDeclarationRHI, *QuadVS, *GenGradientFoldingPS);

			GenGradientFoldingPS->SetParameters(RHICmdList, ImmutableParams.g_ActualDim,
				ImmutableParams.g_InWidth, ImmutableParams.g_OutWidth, ImmutableParams.g_OutHeight,
				ImmutableParams.g_DtxAddressOffset, ImmutableParams.g_DtyAddressOffset);

			GenGradientFoldingPS->SetParameters(RHICmdList, UniformBuffer, DisplacementRenderTarget->TextureRHI);

			DrawPrimitiveUP(RHICmdList, PT_TriangleStrip, 2, PerFrameParams.m_pQuadVB, sizeof(PerFrameParams.m_pQuadVB[0]));

			GenGradientFoldingPS->UnsetParameters(RHICmdList);

			// Generate new mipmaps now
			RHICmdList.GenerateMips(TextureRenderTarget->TextureRHI);
	});
	
}

//////////////////////////////////////////////////////////////////////////
// Spectrum configuration

const FSpectrumData& AVaOceanSimulator::GetSpectrumConfig() const
{
	return SpectrumConfig;
}


//////////////////////////////////////////////////////////////////////////
// Utilities

UTextureRenderTarget2D* AVaOceanSimulator::CreateRenderTarget(bool bInForceLinearGamma, bool bNormalMap, EPixelFormat InPixelFormat, FIntPoint& InTargetSize)
{
	UTextureRenderTarget2D* NewRenderTarget = NewObject<UTextureRenderTarget2D>(this);
	check(NewRenderTarget);

	SetupRenderTarget(NewRenderTarget, bInForceLinearGamma, bNormalMap, InPixelFormat, InTargetSize);

	return NewRenderTarget;
}

void AVaOceanSimulator::SetupRenderTarget(UTextureRenderTarget2D * InRenderTarget, bool bInForceLinearGamma, bool bNormalMap, EPixelFormat InPixelFormat, FIntPoint & InTargetSize)
{
	const FLinearColor ClearColor = bNormalMap ? FLinearColor(0.0f, 0.0f, 0.0f, 0.0f) : FLinearColor(1.0f, 0.0f, 1.0f, 0.0f);

	InRenderTarget->ClearColor = ClearColor;
	InRenderTarget->TargetGamma = 0.0f;
	InRenderTarget->InitCustomFormat(InTargetSize.X, InTargetSize.Y, InPixelFormat, bInForceLinearGamma);
}


================================================
FILE: Source/VaOceanPlugin/Public/IVaOceanPlugin.h
================================================
// Copyright 2014 Vladimir Alyamkin. All Rights Reserved.

#pragma once

#include "ModuleManager.h"


/**
 * The public interface to this module.  In most cases, this interface is only public to sibling modules 
 * within this plugin.
 */
class IVaOceanPlugin : public IModuleInterface
{

public:

	/**
	 * Singleton-like access to this module's interface.  This is just for convenience!
	 * Beware of calling this during the shutdown phase, though.  Your module might have been unloaded already.
	 *
	 * @return Returns singleton instance, loading the module on demand if needed
	 */
	static inline IVaOceanPlugin& Get()
	{
		return FModuleManager::LoadModuleChecked< IVaOceanPlugin >( "VaOceanPlugin" );
	}

	/**
	 * Checks to see if this module is loaded and ready.  It is only valid to call Get() if IsAvailable() returns true.
	 *
	 * @return True if the module is loaded and ready to use
	 */
	static inline bool IsAvailable()
	{
		return FModuleManager::Get().IsModuleLoaded( "VaOceanPlugin" );
	}
};



================================================
FILE: Source/VaOceanPlugin/VaOceanPlugin.Build.cs
================================================
// Copyright 2014 Vladimir Alyamkin. All Rights Reserved.

namespace UnrealBuildTool.Rules
{
	public class VaOceanPlugin : ModuleRules
	{
        public VaOceanPlugin(TargetInfo Target)
		{
			PublicIncludePaths.AddRange(
				new string[] { 
					// ... add public include paths required here ...
				}
				);

			PrivateIncludePaths.AddRange(
				new string[] {
					"VaOceanPlugin/Private",
                    // ... add other private include paths required here ...
				}
				);

			PublicDependencyModuleNames.AddRange(
				new string[]
				{
					"Core",
					"CoreUObject",
                    "Engine",
                    "RenderCore",
                    "ShaderCore",
                    "RHI"
                    // ... add other public dependencies that you statically link with here ...
				}
				);

			PrivateDependencyModuleNames.AddRange(
				new string[]
				{
					// ... add private dependencies that you statically link with here ...
				}
				);

			DynamicallyLoadedModuleNames.AddRange(
				new string[]
				{
					// ... add any modules that your module loads dynamically here ...
				}
				);
		}
	}
}

================================================
FILE: VaOceanPlugin.uplugin
================================================
{
    "FileVersion" : 3,
	
	"FriendlyName" : "VaOcean",
	"Version" : 7,
	"VersionName" : "0.5-a1",
	"CreatedBy" : "Vladimir Alyamkin",
	"CreatedByURL" : "http://alyamkin.com",
	"EngineVersion" : "4.12.0",
	"Description" : "Ocean surface simulation plugin",
	"Category" : "Environment",
	"EnabledByDefault" : false,
	"CanContainContent" : true,
	
	"Modules" :
	[
		{
			"Name" : "VaOceanPlugin",
			"Type" : "Runtime",
			"LoadingPhase" : "PostConfigInit"
		}
	]
}
Download .txt
gitextract_xwtm81v2/

├── .gitignore
├── Content/
│   ├── Blueprints/
│   │   ├── OceanSimulator.uasset
│   │   └── OceanSimulator_Debug.uasset
│   ├── Maps/
│   │   └── Level_Test.umap
│   ├── Materials/
│   │   ├── MI_OceanCS_Example.uasset
│   │   ├── M_FFT_Debug.uasset
│   │   └── M_OceanCS.uasset
│   ├── Meshes/
│   │   └── OceanSurface_Near.uasset
│   └── Textures/
│       ├── RT_Displacement.uasset
│       ├── RT_Gradient.uasset
│       ├── RT_Spectrum_Height.uasset
│       ├── RT_Spectrum_Normals.uasset
│       └── T_Noise_Perline.uasset
├── LICENSE
├── README.md
├── Shaders/
│   ├── VaOcean_CS.usf
│   ├── VaOcean_FFT.usf
│   └── VaOcean_VS_PS.usf
├── Source/
│   └── VaOceanPlugin/
│       ├── Classes/
│       │   ├── VaOceanRadixFFT.h
│       │   ├── VaOceanShaders.h
│       │   ├── VaOceanSimulator.h
│       │   └── VaOceanTypes.h
│       ├── Private/
│       │   ├── VaOceanPlugin.cpp
│       │   ├── VaOceanPluginPrivatePCH.h
│       │   ├── VaOceanRadixFFT.cpp
│       │   ├── VaOceanShaders.cpp
│       │   └── VaOceanSimulator.cpp
│       ├── Public/
│       │   └── IVaOceanPlugin.h
│       └── VaOceanPlugin.Build.cs
└── VaOceanPlugin.uplugin
Download .txt
SYMBOL INDEX (32 symbols across 9 files)

FILE: Source/VaOceanPlugin/Classes/VaOceanRadixFFT.h
  type FRadix008A_CSPerFrame (line 24) | struct FRadix008A_CSPerFrame
  type FRadixPlan512 (line 37) | struct FRadixPlan512

FILE: Source/VaOceanPlugin/Classes/VaOceanShaders.h
  type FUpdateSpectrumCSImmutable (line 26) | struct FUpdateSpectrumCSImmutable
  type FUpdateSpectrumCSPerFrame (line 40) | struct FUpdateSpectrumCSPerFrame
  function class (line 56) | class FUpdateSpectrumCS : public FGlobalShader
  function class (line 190) | class FRadix008A_CS : public FGlobalShader
  function class (line 252) | class FRadix008A_CS2 : public FRadix008A_CS
  type FQuadVertex (line 272) | struct FQuadVertex
  function class (line 279) | class FQuadVertexDeclaration : public FRenderResource
  function class (line 301) | class FQuadVS : public FGlobalShader
  type FUpdateDisplacementPSPerFrame (line 332) | struct FUpdateDisplacementPSPerFrame
  function class (line 348) | class FUpdateDisplacementPS : public FGlobalShader
  type FGenGradientFoldingPSPerFrame (line 443) | struct FGenGradientFoldingPSPerFrame
  function class (line 457) | class FGenGradientFoldingPS : public FGlobalShader

FILE: Source/VaOceanPlugin/Classes/VaOceanSimulator.h
  function VAOCEANPLUGIN_API (line 16) | VAOCEANPLUGIN_API AVaOceanSimulator : public AActor

FILE: Source/VaOceanPlugin/Classes/VaOceanTypes.h
  function FSpectrumData (line 8) | USTRUCT(BlueprintType)

FILE: Source/VaOceanPlugin/Private/VaOceanPlugin.cpp
  class FVaOceanPlugin (line 5) | class FVaOceanPlugin : public IVaOceanPlugin
    method StartupModule (line 8) | virtual void StartupModule() override
    method ShutdownModule (line 13) | virtual void ShutdownModule() override

FILE: Source/VaOceanPlugin/Private/VaOceanRadixFFT.cpp
  function Radix008A (line 5) | void Radix008A(
  function RadixSetPerFrameParams (line 55) | void RadixSetPerFrameParams(FRadixPlan512* Plan,
  function RadixCreatePlan (line 72) | void RadixCreatePlan(FRadixPlan512* Plan, uint32 Slices)
  function RadixDestroyPlan (line 112) | void RadixDestroyPlan(FRadixPlan512* Plan)
  function RadixCompute (line 119) | void RadixCompute(

FILE: Source/VaOceanPlugin/Private/VaOceanSimulator.cpp
  function Gauss (line 19) | float Gauss()
  function Phillips (line 36) | float Phillips(FVector2D K, FVector2D W, float v, float a, float dir_dep...
  function ENQUEUE_UNIQUE_RENDER_COMMAND_FOURPARAMETER (line 372) | ENQUEUE_UNIQUE_RENDER_COMMAND_FOURPARAMETER(
  function UTextureRenderTarget2D (line 426) | UTextureRenderTarget2D* AVaOceanSimulator::CreateRenderTarget(bool bInFo...

FILE: Source/VaOceanPlugin/Public/IVaOceanPlugin.h
  function class (line 12) | class IVaOceanPlugin : public IModuleInterface
  function IsAvailable (line 33) | static inline bool IsAvailable()

FILE: Source/VaOceanPlugin/VaOceanPlugin.Build.cs
  class VaOceanPlugin (line 5) | public class VaOceanPlugin : ModuleRules
    method VaOceanPlugin (line 7) | public VaOceanPlugin(TargetInfo Target)
Condensed preview — 30 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (67K chars).
[
  {
    "path": ".gitignore",
    "chars": 203,
    "preview": "# Compiled Object files\n*.slo\n*.lo\n*.o\n*.obj\n\n# Compiled Dynamic libraries\n*.so\n*.dylib\n*.dll\n\n# Compiled Static librari"
  },
  {
    "path": "LICENSE",
    "chars": 1083,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2014 Vladimir Alyamkin\n\nPermission is hereby granted, free of charge, to any person"
  },
  {
    "path": "README.md",
    "chars": 1326,
    "preview": "Welcome to the VaOcean source code!\n===================================\n\n**Attn.! This branch contains archived version "
  },
  {
    "path": "Shaders/VaOcean_CS.usf",
    "chars": 1667,
    "preview": "// Copyright 2014 Vladimir Alyamkin. All Rights Reserved.\n\n#include \"Common.usf\"\n\n#define PI 3.1415926536f\n#define BLOCK"
  },
  {
    "path": "Shaders/VaOcean_FFT.usf",
    "chars": 3784,
    "preview": "// Copyright 2014 Vladimir Alyamkin. All Rights Reserved.\n\n#include \"Common.usf\"\n\n#define COS_PI_4_16 0.7071067811865475"
  },
  {
    "path": "Shaders/VaOcean_VS_PS.usf",
    "chars": 3094,
    "preview": "// Copyright 2014 Vladimir Alyamkin. All Rights Reserved.\n\n#include \"Common.usf\"\n\n\n/////////////////////////////////////"
  },
  {
    "path": "Source/VaOceanPlugin/Classes/VaOceanRadixFFT.h",
    "chars": 1396,
    "preview": "// Copyright 2014-2016 Vladimir Alyamkin. All Rights Reserved.\n\n#pragma once\n\n#include \"VaOceanPluginPrivatePCH.h\"\n#incl"
  },
  {
    "path": "Source/VaOceanPlugin/Classes/VaOceanShaders.h",
    "chars": 16463,
    "preview": "// Copyright 2014-2016 Vladimir Alyamkin. All Rights Reserved.\n\n#pragma once\n\n#include \"VaOceanPluginPrivatePCH.h\"\n#incl"
  },
  {
    "path": "Source/VaOceanPlugin/Classes/VaOceanSimulator.h",
    "chars": 4932,
    "preview": "// Copyright 2014-2016 Vladimir Alyamkin. All Rights Reserved.\n\n#pragma once\n\n#include \"VaOceanTypes.h\"\n#include \"VaOcea"
  },
  {
    "path": "Source/VaOceanPlugin/Classes/VaOceanTypes.h",
    "chars": 1623,
    "preview": "// Copyright 2014 Vladimir Alyamkin. All Rights Reserved.\n\n#pragma once\n\n#include \"VaOceanTypes.generated.h\"\n\n/** Philli"
  },
  {
    "path": "Source/VaOceanPlugin/Private/VaOceanPlugin.cpp",
    "chars": 366,
    "preview": "// Copyright 2014 Vladimir Alyamkin. All Rights Reserved.\n\n#include \"VaOceanPluginPrivatePCH.h\"\n\nclass FVaOceanPlugin : "
  },
  {
    "path": "Source/VaOceanPlugin/Private/VaOceanPluginPrivatePCH.h",
    "chars": 681,
    "preview": "// Copyright 2014-2016 Vladimir Alyamkin. All Rights Reserved.\n\n#pragma once\n\n#include \"CoreUObject.h\"\n#include \"Engine."
  },
  {
    "path": "Source/VaOceanPlugin/Private/VaOceanRadixFFT.cpp",
    "chars": 4485,
    "preview": "// Copyright 2014-2016 Vladimir Alyamkin. All Rights Reserved.\n\n#include \"VaOceanPluginPrivatePCH.h\"\n\nvoid Radix008A(\n\tF"
  },
  {
    "path": "Source/VaOceanPlugin/Private/VaOceanShaders.cpp",
    "chars": 966,
    "preview": "// Copyright 2014-2016 Vladimir Alyamkin. All Rights Reserved.\n\n#include \"VaOceanPluginPrivatePCH.h\"\n\nIMPLEMENT_SHADER_T"
  },
  {
    "path": "Source/VaOceanPlugin/Private/VaOceanSimulator.cpp",
    "chars": 17629,
    "preview": "// Copyright 2014-2016 Vladimir Alyamkin. All Rights Reserved.\n\n#include \"VaOceanPluginPrivatePCH.h\"\n\n#define HALF_SQRT_"
  },
  {
    "path": "Source/VaOceanPlugin/Public/IVaOceanPlugin.h",
    "chars": 1009,
    "preview": "// Copyright 2014 Vladimir Alyamkin. All Rights Reserved.\n\n#pragma once\n\n#include \"ModuleManager.h\"\n\n\n/**\n * The public "
  },
  {
    "path": "Source/VaOceanPlugin/VaOceanPlugin.Build.cs",
    "chars": 1128,
    "preview": "// Copyright 2014 Vladimir Alyamkin. All Rights Reserved.\n\nnamespace UnrealBuildTool.Rules\n{\n\tpublic class VaOceanPlugin"
  },
  {
    "path": "VaOceanPlugin.uplugin",
    "chars": 463,
    "preview": "{\n    \"FileVersion\" : 3,\n\t\n\t\"FriendlyName\" : \"VaOcean\",\n\t\"Version\" : 7,\n\t\"VersionName\" : \"0.5-a1\",\n\t\"CreatedBy\" : \"Vladi"
  }
]

// ... and 12 more files (download for full content)

About this extraction

This page contains the full source code of the ufna/VaOcean GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 30 files (60.8 KB), approximately 18.1k tokens, and a symbol index with 32 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!