private void CreateFinalSkyboxLUT() { int texDepth = (int)_skyboxLUTSize.z; int texWidth = (int)_skyboxLUTSize.x; int texHeight = (int)_skyboxLUTSize.y; int floatSize = sizeof(float); int channels = 4; int texSize = texWidth * texHeight * texDepth; if (_skyboxLUT == null) { _skyboxLUT = new RenderTexture((int)_skyboxLUTSize.x, (int)_skyboxLUTSize.y, 0, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear); _skyboxLUT.volumeDepth = (int)_skyboxLUTSize.z; _skyboxLUT.dimension = UnityEngine.Rendering.TextureDimension.Tex3D; _skyboxLUT.enableRandomWrite = true; _skyboxLUT.name = "SkyboxLUT"; _skyboxLUT.Create(); } ComputeBuffer buffer = new ComputeBuffer(texSize, floatSize * channels); // 4 bytes for float and 4 channels buffer.SetData(_skyboxData); CBUtility.WriteIntoRenderTexture(_skyboxLUT, channels, buffer, FrostbiteWriteShader); buffer.Release(); //SaveTextureAsKTX(_skyboxLUT, "skyboxlut", true); }
public void ReadTextureFromKTX(RenderTexture rtex, String name) { FileStream fs = new FileStream("Assets/Textures/" + name + ".ktx", FileMode.Open); BinaryReader reader = new BinaryReader(fs); // skip header and meta data reader.ReadBytes(36); int texWidth = (int)reader.ReadUInt32(); int texHeight = (int)reader.ReadUInt32(); int texDepth = (int)reader.ReadUInt32(); int channelCount = 4; int channelSize = 1; int texSize = texWidth * texHeight * texDepth; if (rtex == null) { rtex = new RenderTexture(texWidth, texHeight, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear); rtex.volumeDepth = texDepth; rtex.dimension = UnityEngine.Rendering.TextureDimension.Tex3D; rtex.enableRandomWrite = true; rtex.name = "Noise3DTex"; rtex.filterMode = FilterMode.Trilinear; rtex.wrapMode = TextureWrapMode.Repeat; rtex.Create(); } reader.ReadBytes(16); int bufferSize = (int)reader.ReadUInt32(); ComputeBuffer buffer = new ComputeBuffer(texSize, channelSize * channelCount); // 4 bytes for float and 4 channels buffer.SetData(reader.ReadBytes(bufferSize)); CBUtility.WriteIntoRenderTexture(rtex, channelCount, buffer, FrostbiteWriteShader); buffer.Release(); }
private void CopyDataToTextures() { //Transmittance is responsible for the change in the sun color as it moves //The raw file is a 2D array of 32 bit floats with a range of 0 to 1 string path = Application.streamingAssetsPath + "/Textures/transmittance.raw"; ComputeBuffer buffer = new ComputeBuffer(TRANSMITTANCE_WIDTH * TRANSMITTANCE_HEIGHT, sizeof(float) * TRANSMITTANCE_CHANNELS); CBUtility.WriteIntoRenderTexture(m_transmittance, TRANSMITTANCE_CHANNELS, path, buffer, m_writeData); buffer.Release(); //Inscatter is responsible for the change in the sky color as the sun moves //The raw file is a 4D array of 32 bit floats with a range of 0 to 1.589844 //As there is not such thing as a 4D texture the data is packed into a 3D texture //and the shader manually performs the sample for the 4th dimension path = Application.streamingAssetsPath + "/Textures/inscatter.raw"; buffer = new ComputeBuffer(INSCATTER_WIDTH * INSCATTER_HEIGHT * INSCATTER_DEPTH, sizeof(float) * INSCATTER_CHANNELS); CBUtility.WriteIntoRenderTexture(m_inscatter, INSCATTER_CHANNELS, path, buffer, m_writeData); buffer.Release(); //The raw file is a 2D array of 32 bit floats with a range of 0 to 1 path = Application.streamingAssetsPath + "/Textures/irradiance.raw"; buffer = new ComputeBuffer(IRRADIANCE_WIDTH * IRRADIANCE_HEIGHT, sizeof(float) * IRRADIANCE_CHANNELS); CBUtility.WriteIntoRenderTexture(m_irradiance, IRRADIANCE_CHANNELS, path, buffer, m_writeData); buffer.Release(); }
private void CreateWTable() { // Some values need for the InitWaveSpectrum function can be precomputed var uv = Vector2.zero; var st = Vector2.zero; float k1, k2, k3, k4, w1, w2, w3, w4; var table = new float[FourierGridSize * FourierGridSize * 4]; for (int x = 0; x < FourierGridSize; x++) { for (int y = 0; y < FourierGridSize; y++) { uv = new Vector2(x, y) / MapSize; st.x = uv.x > 0.5f ? uv.x - 1.0f : uv.x; st.y = uv.y > 0.5f ? uv.y - 1.0f : uv.y; k1 = (st * InverseGridSizes.x).magnitude; k2 = (st * InverseGridSizes.y).magnitude; k3 = (st * InverseGridSizes.z).magnitude; k4 = (st * InverseGridSizes.w).magnitude; w1 = Mathf.Sqrt(9.81f * k1 * (1.0f + k1 * k1 / (WAVE_KM * WAVE_KM))); w2 = Mathf.Sqrt(9.81f * k2 * (1.0f + k2 * k2 / (WAVE_KM * WAVE_KM))); w3 = Mathf.Sqrt(9.81f * k3 * (1.0f + k3 * k3 / (WAVE_KM * WAVE_KM))); w4 = Mathf.Sqrt(9.81f * k4 * (1.0f + k4 * k4 / (WAVE_KM * WAVE_KM))); table[(x + y * FourierGridSize) * 4 + 0] = w1; table[(x + y * FourierGridSize) * 4 + 1] = w2; table[(x + y * FourierGridSize) * 4 + 2] = w3; table[(x + y * FourierGridSize) * 4 + 3] = w4; } } // Write floating point data into render texture var buffer = new ComputeBuffer(FourierGridSize * FourierGridSize, sizeof(float) * 4); buffer.SetData(table); CBUtility.WriteIntoRenderTexture(WTable, CBUtility.Channels.RGBA, buffer, GodManager.Instance.WriteData); buffer.ReleaseAndDisposeBuffer(); }
/// <summary> /// Some of the values needed in the InitWaveSpectrum function can be precomputed. /// If the grid sizes change this function must called again. /// </summary> void CreateWTable() { //Some values need for the InitWaveSpectrum function can be precomputed Vector2 uv, st; float k1, k2, k3, k4, w1, w2, w3, w4; float[] table = new float[m_size * m_size * 4]; for (int x = 0; x < m_size; x++) { for (int y = 0; y < m_size; y++) { uv = new Vector2(x, y) / m_fsize; st.x = uv.x > 0.5f ? uv.x - 1.0f : uv.x; st.y = uv.y > 0.5f ? uv.y - 1.0f : uv.y; k1 = (st * m_inverseGridSizes.x).magnitude; k2 = (st * m_inverseGridSizes.y).magnitude; k3 = (st * m_inverseGridSizes.z).magnitude; k4 = (st * m_inverseGridSizes.w).magnitude; w1 = Mathf.Sqrt(9.81f * k1 * (1.0f + k1 * k1 / (WAVE_KM * WAVE_KM))); w2 = Mathf.Sqrt(9.81f * k2 * (1.0f + k2 * k2 / (WAVE_KM * WAVE_KM))); w3 = Mathf.Sqrt(9.81f * k3 * (1.0f + k3 * k3 / (WAVE_KM * WAVE_KM))); w4 = Mathf.Sqrt(9.81f * k4 * (1.0f + k4 * k4 / (WAVE_KM * WAVE_KM))); table[(x + y * m_size) * 4 + 0] = w1; table[(x + y * m_size) * 4 + 1] = w2; table[(x + y * m_size) * 4 + 2] = w3; table[(x + y * m_size) * 4 + 3] = w4; } } //Write floating point data into render texture ComputeBuffer buffer = new ComputeBuffer(m_size * m_size, sizeof(float) * 4); buffer.SetData(table); CBUtility.WriteIntoRenderTexture(m_WTable, 4, buffer, m_writeData); buffer.Release(); }
private void CalculateAO() { Debug.Log("Precomputing AO Started..."); int GRIDRES_AO = 128; int N_AO = 2; var options = new ParallelOptions { MaxDegreeOfParallelism = 4 }; float[] buf = new float[GRIDRES_AO * GRIDRES_AO * GRIDRES_AO * 4]; for (int i = 0; i < GRIDRES_AO; ++i) { for (int j = 0; j < GRIDRES_AO; ++j) { for (int k = 0; k < GRIDRES_AO; ++k) { int off = i + j * GRIDRES_AO + k * GRIDRES_AO * GRIDRES_AO; buf[4 * off] = 0; buf[4 * off + 1] = 0; buf[4 * off + 2] = 0; buf[4 * off + 3] = 0; } } } var indices = PreProcessMesh.GetIndices(0); var vertices = PreProcessMesh.vertices; for (int ni = 0; ni < indices.Length; ni += 3) { int a = indices[ni]; int b = indices[ni + 1]; int c = indices[ni + 2]; float x1 = vertices[a].x, y1 = vertices[a].y, z1 = vertices[a].z; float x2 = vertices[b].x, y2 = vertices[b].y, z2 = vertices[b].z; float x3 = vertices[c].x, y3 = vertices[c].y, z3 = vertices[c].z; x1 = (x1 + 1.0f) / 2.0f; x2 = (x2 + 1.0f) / 2.0f; x3 = (x3 + 1.0f) / 2.0f; y1 = (y1 + 1.0f) / 2.0f; y2 = (y2 + 1.0f) / 2.0f; y3 = (y3 + 1.0f) / 2.0f; z1 = (z1 + 1.0f) / 2.0f; z2 = (z2 + 1.0f) / 2.0f; z3 = (z3 + 1.0f) / 2.0f; double l12 = Mathf.Sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1) + (z2 - z1) * (z2 - z1)); double l23 = Mathf.Sqrt((x3 - x2) * (x3 - x2) + (y3 - y2) * (y3 - y2) + (z3 - z2) * (z3 - z2)); double l31 = Mathf.Sqrt((x1 - x3) * (x1 - x3) + (y1 - y3) * (y1 - y3) + (z1 - z3) * (z1 - z3)); if (l12 > l23 && l12 > l31) { Swap(ref a, ref c); Swap(ref x1, ref x3); Swap(ref y1, ref y3); Swap(ref z1, ref z3); Swap(ref l12, ref l23); } else if (l31 > l12 && l31 > l23) { Swap(ref a, ref b); Swap(ref x1, ref x2); Swap(ref y1, ref y2); Swap(ref z1, ref z2); Swap(ref l31, ref l23); } int n12 = (int)(Math.Ceiling(l12 * GRIDRES_AO) * 2.0); int n13 = (int)(Math.Ceiling(l31 * GRIDRES_AO) * 2.0); Parallel.For(0, n12 - 1, i => { var u = (double)i / n12; Parallel.For(0, n13 - 1, j => { var v = (double)j / n13; if (u + v < 1.0) { var x = x1 + u * (x2 - x1) + v * (x3 - x1); var y = y1 + u * (y2 - y1) + v * (y3 - y1); var z = z1 + u * (z2 - z1) + v * (z3 - z1); int ix = (int)(x * GRIDRES_AO); int iy = (int)(y * GRIDRES_AO); int iz = (int)(z * GRIDRES_AO); if (ix >= 0 && ix < GRIDRES_AO && iy >= 0 && iy < GRIDRES_AO && iz >= 0 && iz < GRIDRES_AO) { int off = 4 * (ix + iy * GRIDRES_AO + iz * GRIDRES_AO * GRIDRES_AO); buf[off] = 255; buf[off + 1] = 255; buf[off + 2] = 255; buf[off + 3] = 255; } } }); }); } Debug.Log("Precomputing AO Mesh Passed..."); double[] vocc = new double[GRIDRES_AO * GRIDRES_AO * GRIDRES_AO]; for (int i = 0; i < GRIDRES_AO * GRIDRES_AO * GRIDRES_AO; ++i) { vocc[i] = 1.0; } double zmax = Math.Abs(Z); double zmin = -Math.Abs(Z); Parallel.For(0, N_AO - 1, options, i => { var theta = (i + 0.5) / N_AO * Math.PI / 2.0; var dtheta = 1.0 / N_AO * Math.PI / 2.0; Parallel.For(0, (4 * N_AO) - 1, options, j => { var phi = (j + 0.5) / (4 * N_AO) * 2.0 * Math.PI; var dphi = 1.0 / (4 * N_AO) * 2.0 * Math.PI; var docc = Math.Cos(theta) * Math.Sin(theta) * dtheta * dphi / Math.PI; if ((i * 4 * N_AO + j) % 4 == 0) { Debug.Log(string.Format("Precomputing AO Step {0} of {1}", i * 4 * N_AO + j, 4 * N_AO * N_AO)); } Vector3d uz = new Vector3d(Math.Cos(phi) * Math.Sin(theta), Math.Sin(phi) * Math.Sin(theta), Math.Cos(theta)); Vector3d ux = uz.z.EpsilonEquals(1.0, 0.0000001) ? new Vector3d(1.0, 0.0, 0.0) : new Vector3d(-uz.y, uz.x, 0.0).Normalized(); Vector3d uy = uz.Cross(ux); Matrix3x3d toView = new Matrix3x3d(ux.x, ux.y, ux.z, uy.x, uy.y, uy.z, uz.x, uz.y, uz.z); Matrix3x3d toVol = new Matrix3x3d(ux.x, uy.x, uz.x, ux.y, uy.y, uz.y, ux.z, uy.z, uz.z); Box3d b = new Box3d(); b = b.Enlarge(toView * new Vector3d(-1.0, -1.0, zmin)); b = b.Enlarge(toView * new Vector3d(+1.0, -1.0, zmin)); b = b.Enlarge(toView * new Vector3d(-1.0, +1.0, zmin)); b = b.Enlarge(toView * new Vector3d(+1.0, +1.0, zmin)); b = b.Enlarge(toView * new Vector3d(-1.0, -1.0, zmax)); b = b.Enlarge(toView * new Vector3d(+1.0, -1.0, zmax)); b = b.Enlarge(toView * new Vector3d(-1.0, +1.0, zmax)); b = b.Enlarge(toView * new Vector3d(+1.0, +1.0, zmax)); int nx = (int)((b.Max.x - b.Min.x) * GRIDRES_AO / 2); int ny = (int)((b.Max.y - b.Min.y) * GRIDRES_AO / 2); int nz = (int)((b.Max.z - b.Min.z) * GRIDRES_AO / 2); int[] occ = new int[nx * ny * nz]; for (int v = 0; v < nx * ny * nz; ++v) { occ[v] = 0; } for (int iz = nz - 1; iz >= 0; --iz) { var z = b.Min.z + (iz + 0.5) / nz * (b.Max.z - b.Min.z); for (int iy = 0; iy < ny; ++iy) { var y = b.Min.y + (iy + 0.5) / ny * (b.Max.y - b.Min.y); for (int ix = 0; ix < nx; ++ix) { var x = b.Min.x + (ix + 0.5) / nx * (b.Max.x - b.Min.x); Vector3d p = toVol * new Vector3d(x, y, z); int val = 0; int vx = (int)((p.x + 1.0) / 2.0 * GRIDRES_AO); int vy = (int)((p.y + 1.0) / 2.0 * GRIDRES_AO); int vz = (int)((p.z + 1.0) / 2.0 * GRIDRES_AO); if (vx >= 0 && vx < GRIDRES_AO && vy >= 0 && vy < GRIDRES_AO && vz >= 0 && vz < GRIDRES_AO) { val = buf[4 * (vx + vy * GRIDRES_AO + vz * GRIDRES_AO * GRIDRES_AO) + 3].EpsilonEquals(255.0f) ? 1 : 0; } occ[ix + iy * nx + iz * nx * ny] = val; if (iz != nz - 1) { occ[ix + iy * nx + iz * nx * ny] += occ[ix + iy * nx + (iz + 1) * nx * ny]; } } } } Parallel.For(0, GRIDRES_AO - 1, options, ix => { var x = -1.0 + (ix + 0.5) / GRIDRES_AO * 2.0; Parallel.For(0, GRIDRES_AO - 1, options, iy => { var y = -1.0 + (iy + 0.5) / GRIDRES_AO * 2.0; Parallel.For(0, GRIDRES_AO - 1, options, iz => { var z = -1.0 + (iz + 0.5) / GRIDRES_AO * 2.0; Vector3d p = toView * new Vector3d(x, y, z); int vx = (int)((p.x - b.Min.x) / (b.Max.x - b.Min.x) * nx); int vy = (int)((p.y - b.Min.y) / (b.Max.y - b.Min.y) * ny); int vz = (int)((p.z - b.Min.z) / (b.Max.z - b.Min.z) * nz); if (vx >= 0 && vx < nx && vy >= 0 && vy < ny && vz >= 0 && vz < nz) { int occN = occ[vx + vy * nx + vz * nx * ny]; if (occN > 6) { vocc[ix + iy * GRIDRES_AO + iz * GRIDRES_AO * GRIDRES_AO] -= docc; } } }); }); }); }); }); for (int i = 0; i < GRIDRES_AO; ++i) { for (int j = 0; j < GRIDRES_AO; ++j) { for (int k = 0; k < GRIDRES_AO; ++k) { int off = i + j * GRIDRES_AO + k * GRIDRES_AO * GRIDRES_AO; if (buf[4 * off + 3].EpsilonEquals(255.0f)) { var v = Math.Max(vocc[off], 0.0f) * 255; buf[4 * off] = (float)v; buf[4 * off + 1] = (float)v; buf[4 * off + 2] = (float)v; } } } } GC.Collect(); var cb = new ComputeBuffer(GRIDRES_AO * GRIDRES_AO * GRIDRES_AO, sizeof(float) * 4); PreProcessAORT = RTExtensions.CreateRTexture(GRIDRES_AO, 0, RenderTextureFormat.ARGBFloat, FilterMode.Bilinear, TextureWrapMode.Clamp, GRIDRES_AO); CBUtility.WriteIntoRenderTexture(PreProcessAORT, CBUtility.Channels.RGBA, cb, GodManager.Instance.WriteData); RTUtility.SaveAs8bit(GRIDRES_AO, GRIDRES_AO * GRIDRES_AO, CBUtility.Channels.RGBA, "TreeAO", DestinationFolder, buf, 0.00392156863f); cb.ReleaseAndDisposeBuffer(); Debug.Log("Precomputing AO Completed!"); }
/// <summary> /// Generates the wave spectrum based on the /// settings wind speed, wave amp and wave age. /// If these values change this function must be called again. /// </summary> void GenerateWavesSpectrum() { // Slope variance due to all waves, by integrating over the full spectrum. float theoreticSlopeVariance = 0.0f; float k = 5e-3f; while (k < 1e3f) { float nextK = k * 1.001f; theoreticSlopeVariance += k * k * Spectrum(k, 0, true) * (nextK - k); k = nextK; } float[] spectrum01 = new float[m_size * m_size * 4]; float[] spectrum23 = new float[m_size * m_size * 4]; int idx; float i; float j; float totalSlopeVariance = 0.0f; Vector2 sample12XY; Vector2 sample12ZW; Vector2 sample34XY; Vector2 sample34ZW; UnityEngine.Random.seed = 0; for (int x = 0; x < m_size; x++) { for (int y = 0; y < m_size; y++) { idx = x + y * m_size; i = (x >= m_size / 2) ? (float)(x - m_size) : (float)x; j = (y >= m_size / 2) ? (float)(y - m_size) : (float)y; sample12XY = GetSpectrumSample(i, j, m_gridSizes.x, Mathf.PI / m_gridSizes.x); sample12ZW = GetSpectrumSample(i, j, m_gridSizes.y, Mathf.PI * m_fsize / m_gridSizes.x); sample34XY = GetSpectrumSample(i, j, m_gridSizes.z, Mathf.PI * m_fsize / m_gridSizes.y); sample34ZW = GetSpectrumSample(i, j, m_gridSizes.w, Mathf.PI * m_fsize / m_gridSizes.z); spectrum01[idx * 4 + 0] = sample12XY.x; spectrum01[idx * 4 + 1] = sample12XY.y; spectrum01[idx * 4 + 2] = sample12ZW.x; spectrum01[idx * 4 + 3] = sample12ZW.y; spectrum23[idx * 4 + 0] = sample34XY.x; spectrum23[idx * 4 + 1] = sample34XY.y; spectrum23[idx * 4 + 2] = sample34ZW.x; spectrum23[idx * 4 + 3] = sample34ZW.y; i *= 2.0f * Mathf.PI; j *= 2.0f * Mathf.PI; totalSlopeVariance += GetSlopeVariance(i / m_gridSizes.x, j / m_gridSizes.x, sample12XY); totalSlopeVariance += GetSlopeVariance(i / m_gridSizes.y, j / m_gridSizes.y, sample12ZW); totalSlopeVariance += GetSlopeVariance(i / m_gridSizes.z, j / m_gridSizes.z, sample34XY); totalSlopeVariance += GetSlopeVariance(i / m_gridSizes.w, j / m_gridSizes.w, sample34ZW); } } //Write floating point data into render texture ComputeBuffer buffer = new ComputeBuffer(m_size * m_size, sizeof(float) * 4); buffer.SetData(spectrum01); CBUtility.WriteIntoRenderTexture(m_spectrum01, 4, buffer, m_writeData); buffer.SetData(spectrum23); CBUtility.WriteIntoRenderTexture(m_spectrum23, 4, buffer, m_writeData); buffer.Release(); m_varianceShader.SetFloat("_SlopeVarianceDelta", 0.5f * (theoreticSlopeVariance - totalSlopeVariance)); m_varianceShader.SetFloat("_VarianceSize", (float)m_varianceSize); m_varianceShader.SetFloat("_Size", m_fsize); m_varianceShader.SetVector("_GridSizes", m_gridSizes); m_varianceShader.SetTexture(0, "_Spectrum01", m_spectrum01); m_varianceShader.SetTexture(0, "_Spectrum23", m_spectrum23); m_varianceShader.SetTexture(0, "des", m_variance); m_varianceShader.Dispatch(0, m_varianceSize / 4, m_varianceSize / 4, m_varianceSize / 4); }
void Start() { ComputeShader writeData = Resources.Load <ComputeShader>("Ocean/WriteData"); if (writeData == null) { throw new ArgumentException("Could not find Write compute shader in the resources folder"); } m_skyMap = new RenderTexture(512, 512, 0, RenderTextureFormat.ARGBHalf); m_skyMap.filterMode = FilterMode.Trilinear; m_skyMap.wrapMode = TextureWrapMode.Clamp; m_skyMap.anisoLevel = 9; m_skyMap.useMipMap = true; m_skyMap.Create(); m_transmittance = new RenderTexture(TRANSMITTANCE_WIDTH, TRANSMITTANCE_HEIGHT, 0, RenderTextureFormat.ARGBHalf); m_transmittance.wrapMode = TextureWrapMode.Clamp; m_transmittance.filterMode = FilterMode.Bilinear; m_transmittance.enableRandomWrite = true; m_transmittance.Create(); m_irradiance = new RenderTexture(IRRADIANCE_WIDTH, IRRADIANCE_HEIGHT, 0, RenderTextureFormat.ARGBHalf); m_irradiance.wrapMode = TextureWrapMode.Clamp; m_irradiance.filterMode = FilterMode.Bilinear; m_irradiance.enableRandomWrite = true; m_irradiance.Create(); m_inscatter = new RenderTexture(INSCATTER_WIDTH, INSCATTER_HEIGHT, 0, RenderTextureFormat.ARGBHalf); m_inscatter.volumeDepth = INSCATTER_DEPTH; m_inscatter.wrapMode = TextureWrapMode.Clamp; m_inscatter.filterMode = FilterMode.Bilinear; m_inscatter.isVolume = true; m_inscatter.enableRandomWrite = true; m_inscatter.Create(); //Transmittance is responsible for the change in the sun color as it moves //The raw file is a 2D array of 32 bit floats with a range of 0 to 1 string path = Application.dataPath + "/Resources/Textures/transmittance.raw"; ComputeBuffer buffer = new ComputeBuffer(TRANSMITTANCE_WIDTH * TRANSMITTANCE_HEIGHT, sizeof(float) * TRANSMITTANCE_CHANNELS); CBUtility.WriteIntoRenderTexture(m_transmittance, TRANSMITTANCE_CHANNELS, path, buffer, writeData); buffer.Release(); //Iirradiance is responsible for the change in the sky color as the sun moves //The raw file is a 2D array of 32 bit floats with a range of 0 to 1 path = Application.dataPath + "/Resources/Textures/irradiance.raw"; buffer = new ComputeBuffer(IRRADIANCE_WIDTH * IRRADIANCE_HEIGHT, sizeof(float) * IRRADIANCE_CHANNELS); CBUtility.WriteIntoRenderTexture(m_irradiance, IRRADIANCE_CHANNELS, path, buffer, writeData); buffer.Release(); //Inscatter is responsible for the change in the sky color as the sun moves //The raw file is a 4D array of 32 bit floats with a range of 0 to 1.589844 //As there is not such thing as a 4D texture the data is packed into a 2D texture //and the shader manually performs the sample for the 3rd and 4th dimension path = Application.dataPath + "/Resources/Textures/inscatter.raw"; buffer = new ComputeBuffer(INSCATTER_WIDTH * INSCATTER_HEIGHT * INSCATTER_DEPTH, sizeof(float) * INSCATTER_CHANNELS); CBUtility.WriteIntoRenderTexture(m_inscatter, INSCATTER_CHANNELS, path, buffer, writeData); buffer.Release(); InitMaterial(m_skyMapMaterial); InitMaterial(m_skyMaterial); //ocean mat needs some of these uniforms so may as well set them here InitMaterial(m_oceanMaterial); }
private void GenerateWavesSpectrum() { // Slope variance due to all waves, by integrating over the full spectrum. // Used by the BRDF rendering model var theoreticSlopeVariance = 0.0f; var k = 5e-3f; while (k < 1e3f) { var nextK = k * 1.001f; theoreticSlopeVariance += k * k * Spectrum(k, 0, true) * (nextK - k); k = nextK; } var spectrum01 = new float[FourierGridSize * FourierGridSize * 4]; var spectrum23 = new float[FourierGridSize * FourierGridSize * 4]; int idx; float i; float j; float totalSlopeVariance = 0.0f; Vector2 sample12XY = Vector2.zero; Vector2 sample12ZW = Vector2.zero; Vector2 sample34XY = Vector2.zero; Vector2 sample34ZW = Vector2.zero; Random.InitState(0); for (int x = 0; x < FourierGridSize; x++) { for (int y = 0; y < FourierGridSize; y++) { idx = x + y * FourierGridSize; i = (x >= FourierGridSize / 2) ? (float)(x - FourierGridSize) : (float)x; j = (y >= FourierGridSize / 2) ? (float)(y - FourierGridSize) : (float)y; sample12XY = GetSpectrumSample(i, j, GridSizes.x, Mathf.PI / GridSizes.x); sample12ZW = GetSpectrumSample(i, j, GridSizes.y, Mathf.PI * MapSize / GridSizes.x); sample34XY = GetSpectrumSample(i, j, GridSizes.z, Mathf.PI * MapSize / GridSizes.y); sample34ZW = GetSpectrumSample(i, j, GridSizes.w, Mathf.PI * MapSize / GridSizes.z); spectrum01[idx * 4 + 0] = sample12XY.x; spectrum01[idx * 4 + 1] = sample12XY.y; spectrum01[idx * 4 + 2] = sample12ZW.x; spectrum01[idx * 4 + 3] = sample12ZW.y; spectrum23[idx * 4 + 0] = sample34XY.x; spectrum23[idx * 4 + 1] = sample34XY.y; spectrum23[idx * 4 + 2] = sample34ZW.x; spectrum23[idx * 4 + 3] = sample34ZW.y; i *= 2.0f * Mathf.PI; j *= 2.0f * Mathf.PI; totalSlopeVariance += GetSlopeVariance(i / GridSizes.x, j / GridSizes.x, sample12XY); totalSlopeVariance += GetSlopeVariance(i / GridSizes.y, j / GridSizes.y, sample12ZW); totalSlopeVariance += GetSlopeVariance(i / GridSizes.z, j / GridSizes.z, sample34XY); totalSlopeVariance += GetSlopeVariance(i / GridSizes.w, j / GridSizes.w, sample34ZW); } } //Write floating point data into render texture var buffer = new ComputeBuffer(FourierGridSize * FourierGridSize, sizeof(float) * 4); buffer.SetData(spectrum01); CBUtility.WriteIntoRenderTexture(Spectrum01, CBUtility.Channels.RGBA, buffer, GodManager.Instance.WriteData); buffer.SetData(spectrum23); CBUtility.WriteIntoRenderTexture(Spectrum23, CBUtility.Channels.RGBA, buffer, GodManager.Instance.WriteData); buffer.Release(); var varianceShader = GodManager.Instance.Variance; varianceShader.SetFloat("_SlopeVarianceDelta", 0.5f * (theoreticSlopeVariance - totalSlopeVariance)); varianceShader.SetFloat("_VarianceSize", (float)VarianceSize); varianceShader.SetFloat("_Size", MapSize); varianceShader.SetVector("_GridSizes", GridSizes); varianceShader.SetTexture(0, "_Spectrum01", Spectrum01); varianceShader.SetTexture(0, "_Spectrum23", Spectrum23); varianceShader.SetTexture(0, "des", Variance); varianceShader.Dispatch(0, VarianceSize / 4, VarianceSize / 4, VarianceSize / 4); // Find the maximum value for slope variance buffer = new ComputeBuffer(VarianceSize * VarianceSize * VarianceSize, sizeof(float)); CBUtility.ReadFromRenderTexture(Variance, CBUtility.Channels.R, buffer, GodManager.Instance.ReadData); var varianceData = new float[VarianceSize * VarianceSize * VarianceSize]; buffer.GetData(varianceData); MaxSlopeVariance = 0.0f; for (int v = 0; v < VarianceSize * VarianceSize * VarianceSize; v++) { MaxSlopeVariance = Mathf.Max(MaxSlopeVariance, varianceData[v]); } buffer.Release(); }
/// <summary> /// Creates a series of textures that contain random noise. /// These texture tile together using the Wang Tiling method. /// Used by the UpSample shader to create fractal noise for the terrain elevations. /// </summary> private void CreateDemNoise() { int tileWidth = Cache.GetStorage(0).TileSize; m_noiseTextures = new RenderTexture[6]; int[] layers = new int[] { 0, 1, 3, 5, 7, 15 }; int rand = 1234567; for (int nl = 0; nl < 6; ++nl) { float[] noiseArray = new float[tileWidth * tileWidth]; int l = layers[nl]; ComputeBuffer buffer = new ComputeBuffer(tileWidth * tileWidth, sizeof(float)); // corners for (int j = 0; j < tileWidth; ++j) { for (int i = 0; i < tileWidth; ++i) { noiseArray[i + j * tileWidth] = 0.0f; } } // bottom border Random.InitState((l & 1) == 0 ? 7654321 : 5647381); for (int h = 5; h <= tileWidth / 2; ++h) { float N = Rand(); noiseArray[h + 2 * tileWidth] = N; noiseArray[(tileWidth - 1 - h) + 2 * tileWidth] = N; } for (int v = 3; v < 5; ++v) { for (int h = 5; h < tileWidth - 5; ++h) { float N = Rand(); noiseArray[h + v * tileWidth] = N; noiseArray[(tileWidth - 1 - h) + (4 - v) * tileWidth] = N; } } // right border Random.InitState((l & 2) == 0 ? 7654321 : 5647381); for (int v = 5; v <= tileWidth / 2; ++v) { float N = Rand(); noiseArray[(tileWidth - 3) + v * tileWidth] = N; noiseArray[(tileWidth - 3) + (tileWidth - 1 - v) * tileWidth] = N; } for (int h = tileWidth - 4; h >= tileWidth - 5; --h) { for (int v = 5; v < tileWidth - 5; ++v) { float N = Rand(); noiseArray[h + v * tileWidth] = N; noiseArray[(2 * tileWidth - 6 - h) + (tileWidth - 1 - v) * tileWidth] = N; } } // top border Random.InitState((l & 4) == 0 ? 7654321 : 5647381); for (int h = 5; h <= tileWidth / 2; ++h) { float N = Rand(); noiseArray[h + (tileWidth - 3) * tileWidth] = N; noiseArray[(tileWidth - 1 - h) + (tileWidth - 3) * tileWidth] = N; } for (int v = tileWidth - 2; v < tileWidth; ++v) { for (int h = 5; h < tileWidth - 5; ++h) { float N = Rand(); noiseArray[h + v * tileWidth] = N; noiseArray[(tileWidth - 1 - h) + (2 * tileWidth - 6 - v) * tileWidth] = N; } } // left border Random.InitState((l & 8) == 0 ? 7654321 : 5647381); for (int v = 5; v <= tileWidth / 2; ++v) { float N = Rand(); noiseArray[2 + v * tileWidth] = N; noiseArray[2 + (tileWidth - 1 - v) * tileWidth] = N; } for (int h = 1; h >= 0; --h) { for (int v = 5; v < tileWidth - 5; ++v) { float N = Rand(); noiseArray[h + v * tileWidth] = N; noiseArray[(4 - h) + (tileWidth - 1 - v) * tileWidth] = N; } } // center Random.InitState(rand); for (int v = 5; v < tileWidth - 5; ++v) { for (int h = 5; h < tileWidth - 5; ++h) { float N = Rand(); noiseArray[h + v * tileWidth] = N; } } //randomize for next texture rand = (rand * 1103515245 + 12345) & 0x7FFFFFFF; m_noiseTextures[nl] = new RenderTexture(tileWidth, tileWidth, 0, RenderTextureFormat.RHalf); m_noiseTextures[nl].wrapMode = TextureWrapMode.Repeat; m_noiseTextures[nl].filterMode = FilterMode.Point; m_noiseTextures[nl].enableRandomWrite = true; m_noiseTextures[nl].Create(); //write data into render texture buffer.SetData(noiseArray); CBUtility.WriteIntoRenderTexture(m_noiseTextures[nl], 1, buffer, World.WriteData); buffer.Release(); } }
/// <summary> /// This function creates the elevations data and is called by the CreateTileTask when the task is run by the schedular /// The functions needs the tiles parent data to have already been created. If it has not the program will abort. /// </summary> public override void DoCreateTile(int level, int tx, int ty, List <Slot> slot) { GPUSlot gpuSlot = slot[0] as GPUSlot; int tileWidth = gpuSlot.Owner.TileSize; int b = Border * 2 + 1; int tileSize = tileWidth - b; GPUSlot parentGpuSlot = null; Tile parentTile = null; if (level > 0) { parentTile = FindTile(level - 1, tx / 2, ty / 2, false, true); if (parentTile != null) { parentGpuSlot = parentTile.GetSlot(0) as GPUSlot; } else { throw new MissingTileException("Find parent tile failed"); } } float rootQuadSize = (float)TerrainNode.Root.Length; Vector4 tileWSD = new Vector4(); tileWSD.x = tileWidth; tileWSD.y = rootQuadSize / (1 << level) / tileSize; tileWSD.z = (tileWidth - b) / (World.GridResolution - 1.0f); tileWSD.w = 0.0f; m_upsampleMat.SetVector(m_uniforms.tileWSD, tileWSD); if (level > 0) { RenderTexture tex = parentGpuSlot.Texture; m_upsampleMat.SetTexture(m_uniforms.coarseLevelSampler, tex); float dx = (tx % 2) * (tileSize / 2); float dy = (ty % 2) * (tileSize / 2); Vector4 coarseLevelOSL = new Vector4(dx / tex.width, dy / tex.height, 1.0f / tex.width, 0.0f); m_upsampleMat.SetVector(m_uniforms.coarseLevelOSL, coarseLevelOSL); } else { m_upsampleMat.SetVector(m_uniforms.coarseLevelOSL, new Vector4(-1.0f, -1.0f, -1.0f, -1.0f)); } if (m_residualProducer != null && m_residualProducer.HasTile(level, tx, ty)) { Tile residualTile = m_residualProducer.FindTile(level, tx, ty, false, true); CPUSlot <float> residualSlot = null; if (residualTile != null) { residualSlot = residualTile.GetSlot(0) as CPUSlot <float>; } else { throw new MissingTileException("Find residual tile failed"); } //Must clear residual tex before use or terrain will have artifacts at the seams. Not sure why. RTUtility.ClearColor(m_residualTex, Color.clear); m_residualBuffer.SetData(residualSlot.Data); CBUtility.WriteIntoRenderTexture(m_residualTex, 1, m_residualBuffer, World.WriteData); m_upsampleMat.SetTexture(m_uniforms.residualSampler, m_residualTex); m_upsampleMat.SetVector(m_uniforms.residualOSH, new Vector4(0.25f / tileWidth, 0.25f / tileWidth, 2.0f / tileWidth, 1.0f)); } else { m_upsampleMat.SetTexture(m_uniforms.residualSampler, null); m_upsampleMat.SetVector(m_uniforms.residualOSH, new Vector4(0.0f, 0.0f, 1.0f, 0.0f)); } float rs = level < m_noiseAmp.Length ? m_noiseAmp[level] : 0.0f; int noiseL = 0; int face = TerrainNode.Face; if (rs != 0.0f) { if (face == 1) { int offset = 1 << level; int bottomB = m_noise.Noise2D(tx + 0.5f, ty + offset) > 0.0f ? 1 : 0; int rightB = (tx == offset - 1 ? m_noise.Noise2D(ty + offset + 0.5f, offset) : m_noise.Noise2D(tx + 1.0f, ty + offset + 0.5f)) > 0.0f ? 2 : 0; int topB = (ty == offset - 1 ? m_noise.Noise2D((3.0f * offset - 1.0f - tx) + 0.5f, offset) : m_noise.Noise2D(tx + 0.5f, ty + offset + 1.0f)) > 0.0f ? 4 : 0; int leftB = (tx == 0 ? m_noise.Noise2D((4.0f * offset - 1.0f - ty) + 0.5f, offset) : m_noise.Noise2D(tx, ty + offset + 0.5f)) > 0.0f ? 8 : 0; noiseL = bottomB + rightB + topB + leftB; } else if (face == 6) { int offset = 1 << level; int bottomB = (ty == 0 ? m_noise.Noise2D((3.0f * offset - 1.0f - tx) + 0.5f, 0) : m_noise.Noise2D(tx + 0.5f, ty - offset)) > 0.0f ? 1 : 0; int rightB = (tx == offset - 1.0f ? m_noise.Noise2D((2.0f * offset - 1.0f - ty) + 0.5f, 0) : m_noise.Noise2D(tx + 1.0f, ty - offset + 0.5f)) > 0.0f ? 2 : 0; int topB = m_noise.Noise2D(tx + 0.5f, ty - offset + 1.0f) > 0.0f ? 4 : 0; int leftB = (tx == 0 ? m_noise.Noise2D(3.0f * offset + ty + 0.5f, 0) : m_noise.Noise2D(tx, ty - offset + 0.5f)) > 0.0f ? 8 : 0; noiseL = bottomB + rightB + topB + leftB; } else { int offset = (1 << level) * (face - 2); int bottomB = m_noise.Noise2D(tx + offset + 0.5f, ty) > 0.0f ? 1 : 0; int rightB = m_noise.Noise2D((tx + offset + 1) % (4 << level), ty + 0.5f) > 0.0f ? 2 : 0; int topB = m_noise.Noise2D(tx + offset + 0.5f, ty + 1.0f) > 0.0f ? 4 : 0; int leftB = m_noise.Noise2D(tx + offset, ty + 0.5f) > 0.0f ? 8 : 0; noiseL = bottomB + rightB + topB + leftB; } } int[] noiseRs = new int[] { 0, 0, 1, 0, 2, 0, 1, 0, 3, 3, 1, 3, 2, 2, 1, 0 }; int noiseR = noiseRs[noiseL]; int[] noiseLs = new int[] { 0, 1, 1, 2, 1, 3, 2, 4, 1, 2, 3, 4, 2, 4, 4, 5 }; noiseL = noiseLs[noiseL]; m_upsampleMat.SetTexture(m_uniforms.noiseSampler, m_noiseTextures[noiseL]); m_upsampleMat.SetVector(m_uniforms.noiseUVLH, new Vector4(noiseR, (noiseR + 1) % 4, 0, rs)); Graphics.Blit(null, gpuSlot.Texture, m_upsampleMat); base.DoCreateTile(level, tx, ty, slot); }
private void GenerateWavesSpectrum() { // Slope variance due to all waves, by integrating over the full spectrum. // Used by the BRDF rendering model float theoreticSlopeVariance = 0.0f; float k = 5e-3f; while (k < 1e3f) { float nextK = k * 1.001f; theoreticSlopeVariance += k * k * Spectrum(k, 0, true) * (nextK - k); k = nextK; } float[] spectrum01 = new float[m_fourierGridSize * m_fourierGridSize * 4]; float[] spectrum23 = new float[m_fourierGridSize * m_fourierGridSize * 4]; int idx; float i; float j; float totalSlopeVariance = 0.0f; Vector2 sample12XY; Vector2 sample12ZW; Vector2 sample34XY; Vector2 sample34ZW; Random.InitState(0); for (int x = 0; x < m_fourierGridSize; x++) { for (int y = 0; y < m_fourierGridSize; y++) { idx = x + y * m_fourierGridSize; i = (x >= m_fourierGridSize / 2) ? (float)(x - m_fourierGridSize) : (float)x; j = (y >= m_fourierGridSize / 2) ? (float)(y - m_fourierGridSize) : (float)y; sample12XY = GetSpectrumSample(i, j, m_gridSizes.x, Mathf.PI / m_gridSizes.x); sample12ZW = GetSpectrumSample(i, j, m_gridSizes.y, Mathf.PI * m_fsize / m_gridSizes.x); sample34XY = GetSpectrumSample(i, j, m_gridSizes.z, Mathf.PI * m_fsize / m_gridSizes.y); sample34ZW = GetSpectrumSample(i, j, m_gridSizes.w, Mathf.PI * m_fsize / m_gridSizes.z); spectrum01[idx * 4 + 0] = sample12XY.x; spectrum01[idx * 4 + 1] = sample12XY.y; spectrum01[idx * 4 + 2] = sample12ZW.x; spectrum01[idx * 4 + 3] = sample12ZW.y; spectrum23[idx * 4 + 0] = sample34XY.x; spectrum23[idx * 4 + 1] = sample34XY.y; spectrum23[idx * 4 + 2] = sample34ZW.x; spectrum23[idx * 4 + 3] = sample34ZW.y; i *= 2.0f * Mathf.PI; j *= 2.0f * Mathf.PI; totalSlopeVariance += GetSlopeVariance(i / m_gridSizes.x, j / m_gridSizes.x, sample12XY); totalSlopeVariance += GetSlopeVariance(i / m_gridSizes.y, j / m_gridSizes.y, sample12ZW); totalSlopeVariance += GetSlopeVariance(i / m_gridSizes.z, j / m_gridSizes.z, sample34XY); totalSlopeVariance += GetSlopeVariance(i / m_gridSizes.w, j / m_gridSizes.w, sample34ZW); } } //Write floating point data into render texture ComputeBuffer buffer = new ComputeBuffer(m_fourierGridSize * m_fourierGridSize, sizeof(float) * 4); buffer.SetData(spectrum01); CBUtility.WriteIntoRenderTexture(m_spectrum01, 4, buffer, World.WriteData); buffer.SetData(spectrum23); CBUtility.WriteIntoRenderTexture(m_spectrum23, 4, buffer, World.WriteData); buffer.Release(); m_varianceShader.SetFloat("_SlopeVarianceDelta", 0.5f * (theoreticSlopeVariance - totalSlopeVariance)); m_varianceShader.SetFloat("_VarianceSize", (float)m_varianceSize); m_varianceShader.SetFloat("_Size", m_fsize); m_varianceShader.SetVector("_GridSizes", m_gridSizes); m_varianceShader.SetTexture(0, "_Spectrum01", m_spectrum01); m_varianceShader.SetTexture(0, "_Spectrum23", m_spectrum23); m_varianceShader.SetTexture(0, "des", m_variance); m_varianceShader.Dispatch(0, m_varianceSize / 4, m_varianceSize / 4, m_varianceSize / 4); //Find the maximum value for slope variance buffer = new ComputeBuffer(m_varianceSize * m_varianceSize * m_varianceSize, sizeof(float)); CBUtility.ReadFromRenderTexture(m_variance, 1, buffer, World.ReadData); float[] varianceData = new float[m_varianceSize * m_varianceSize * m_varianceSize]; buffer.GetData(varianceData); m_maxSlopeVariance = 0.0f; for (int v = 0; v < m_varianceSize * m_varianceSize * m_varianceSize; v++) { m_maxSlopeVariance = Mathf.Max(m_maxSlopeVariance, varianceData[v]); } buffer.Release(); }
/// <summary> /// This function creates the elevations data and is called by the <see cref="Tile.Tasks.CreateTileTask"/> when the task is run by the <see cref="Utilities.Schedular"/>. /// The functions needs the tiles parent data to have already been created. If it has not the program will abort. /// </summary> /// <param name="level"></param> /// <param name="tx"></param> /// <param name="ty"></param> /// <param name="slot"></param> public override void DoCreateTile(int level, int tx, int ty, List <TileStorage.Slot> slot) { var gpuSlot = slot[0] as GPUTileStorage.GPUSlot; if (gpuSlot == null) { throw new NullReferenceException("gpuSlot"); } var tileWidth = gpuSlot.Owner.TileSize; var tileSize = tileWidth - (1 + GetBorder() * 2); GPUTileStorage.GPUSlot parentGpuSlot = null; var upsample = level > 0; var parentTile = FindTile(level - 1, tx / 2, ty / 2, false, true); // TODO : Make it classwide... var residualTileSize = GetTileSize(0); var residualTexture = RTExtensions.CreateRTexture(residualTileSize, 0, RenderTextureFormat.RFloat, FilterMode.Point, TextureWrapMode.Clamp); var residualBuffer = new ComputeBuffer(residualTileSize * residualTileSize, sizeof(float)); if (ResidualProducer != null) { if (ResidualProducer.HasTile(level, tx, ty)) { if (ResidualProducer.IsGPUProducer) { GPUTileStorage.GPUSlot residualGpuSlot = null; var residualTile = ResidualProducer.FindTile(level, tx, ty, false, true); if (residualTile != null) { residualGpuSlot = residualTile.GetSlot(0) as GPUTileStorage.GPUSlot; } else { throw new MissingTileException("Find residual tile failed"); } if (residualGpuSlot == null) { throw new MissingTileException("Find parent tile failed"); } UpSampleMaterial.SetTexture("_ResidualSampler", residualGpuSlot.Texture); UpSampleMaterial.SetVector("_ResidualOSH", new Vector4(0.25f / (float)tileWidth, 0.25f / (float)tileWidth, 2.0f / (float)tileWidth, 1.0f)); } else { CPUTileStorage.CPUSlot <float> residualCPUSlot = null; var residualTile = ResidualProducer.FindTile(level, tx, ty, false, true); if (residualTile != null) { residualCPUSlot = residualTile.GetSlot(0) as CPUTileStorage.CPUSlot <float>; } else { throw new MissingTileException("Find residual tile failed"); } if (residualCPUSlot == null) { throw new MissingTileException("Find parent tile failed"); } residualBuffer.SetData(residualCPUSlot.Data); RTUtility.ClearColor(residualTexture); CBUtility.WriteIntoRenderTexture(residualTexture, CBUtility.Channels.R, residualBuffer, GodManager.Instance.WriteData); //RTUtility.SaveAs8bit(residualTileSize, residualTileSize, CBUtility.Channels.R, string.Format("Residual_{0}_{1}-{2}-{3}", TerrainNode.name, level, tx, ty), "/Resources/Preprocess/Textures/Debug/", residualCPUSlot.Data); UpSampleMaterial.SetTexture("_ResidualSampler", residualTexture); UpSampleMaterial.SetVector("_ResidualOSH", new Vector4(0.25f / (float)tileWidth, 0.25f / (float)tileWidth, 2.0f / (float)tileWidth, 1.0f)); } } else { UpSampleMaterial.SetTexture("_ResidualSampler", null); UpSampleMaterial.SetVector("_ResidualOSH", new Vector4(0.0f, 0.0f, 1.0f, 0.0f)); } } else { UpSampleMaterial.SetTexture("_ResidualSampler", null); UpSampleMaterial.SetVector("_ResidualOSH", new Vector4(0.0f, 0.0f, 1.0f, 0.0f)); } if (upsample) { if (parentTile != null) { parentGpuSlot = parentTile.GetSlot(0) as GPUTileStorage.GPUSlot; } else { throw new MissingTileException(string.Format("Find parent tile failed! {0}:{1}-{2}", level - 1, tx / 2, ty / 2)); } } if (parentGpuSlot == null && upsample) { throw new NullReferenceException("parentGpuSlot"); } var rootQuadSize = TerrainNode.TerrainQuadRoot.Length; var tileWSD = Vector4.zero; tileWSD.x = (float)tileWidth; tileWSD.y = (float)rootQuadSize / (float)(1 << level) / (float)tileSize; tileWSD.z = (float)tileSize / (float)(TerrainNode.ParentBody.GridResolution - 1); tileWSD.w = 0.0f; var tileScreenSize = (0.5 + (float)GetBorder()) / (tileWSD.x - 1 - (float)GetBorder() * 2); var tileSD = new Vector2d(tileScreenSize, 1.0 + tileScreenSize * 2.0); UpSampleMaterial.SetVector("_TileWSD", tileWSD); UpSampleMaterial.SetVector("_TileSD", tileSD.ToVector2()); if (upsample) { var parentTexture = parentGpuSlot.Texture; var dx = (float)(tx % 2) * (float)(tileSize / 2.0f); var dy = (float)(ty % 2) * (float)(tileSize / 2.0f); var coarseLevelOSL = new Vector4(dx / (float)parentTexture.width, dy / (float)parentTexture.height, 1.0f / (float)parentTexture.width, 0.0f); UpSampleMaterial.SetTexture("_CoarseLevelSampler", parentTexture); UpSampleMaterial.SetVector("_CoarseLevelOSL", coarseLevelOSL); } else { UpSampleMaterial.SetTexture("_CoarseLevelSampler", null); UpSampleMaterial.SetVector("_CoarseLevelOSL", new Vector4(-1.0f, -1.0f, -1.0f, -1.0f)); } var rs = level < NoiseAmplitudes.Length ? NoiseAmplitudes[level] : 0.0f; var offset = new Vector4d(((double)tx / (1 << level) - 0.5) * rootQuadSize, ((double)ty / (1 << level) - 0.5) * rootQuadSize, rootQuadSize / (1 << level), TerrainNode.ParentBody.Size); UpSampleMaterial.SetFloat("_Amplitude", rs / (TerrainNode.ParentBody.Amplitude / 10.0f)); UpSampleMaterial.SetFloat("_Frequency", TerrainNode.ParentBody.Frequency * (1 << level)); UpSampleMaterial.SetVector("_Offset", offset.ToVector4()); UpSampleMaterial.SetMatrix("_LocalToWorld", TerrainNode.FaceToLocal.ToMatrix4x4()); if (TerrainNode.ParentBody.TCCPS != null) { TerrainNode.ParentBody.TCCPS.SetUniforms(UpSampleMaterial); } Graphics.Blit(null, gpuSlot.Texture, UpSampleMaterial); residualTexture.ReleaseAndDestroy(); residualBuffer.ReleaseAndDisposeBuffer(); base.DoCreateTile(level, tx, ty, slot); }
/// <summary> /// Creates a series of textures that contain random noise. /// These texture tile together using the Wang Tiling method. /// Used by the UpSample shader to create fractal noise for the terrain elevations. /// </summary> private void CreateDemNoise() { var tileWidth = Cache.GetStorage(0).TileSize; NoiseTextures = new RenderTexture[6]; var layers = new int[] { 0, 1, 3, 5, 7, 15 }; var rand = 1234567; for (byte nl = 0; nl < 6; ++nl) { var noiseArray = new float[tileWidth * tileWidth]; var l = layers[nl]; var buffer = new ComputeBuffer(tileWidth * tileWidth, sizeof(float)); for (int j = 0; j < tileWidth; ++j) { for (int i = 0; i < tileWidth; ++i) { noiseArray[i + j * tileWidth] = Noise.Noise2D(i, j); } } // Corners for (int j = 0; j < tileWidth; ++j) { for (int i = 0; i < tileWidth; ++i) { noiseArray[i + j * tileWidth] = 0.0f; } } // Bottom border Random.InitState((l & 1) == 0 ? 7654321 : 5647381); for (int h = 5; h <= tileWidth / 2; ++h) { var N = RandomValue(); noiseArray[h + 2 * tileWidth] = N; noiseArray[(tileWidth - 1 - h) + 2 * tileWidth] = N; } for (int v = 3; v < 5; ++v) { for (int h = 5; h < tileWidth - 5; ++h) { var N = RandomValue(); noiseArray[h + v * tileWidth] = N; noiseArray[(tileWidth - 1 - h) + (4 - v) * tileWidth] = N; } } // Right border Random.InitState((l & 2) == 0 ? 7654321 : 5647381); for (int v = 5; v <= tileWidth / 2; ++v) { var N = RandomValue(); noiseArray[(tileWidth - 3) + v * tileWidth] = N; noiseArray[(tileWidth - 3) + (tileWidth - 1 - v) * tileWidth] = N; } for (int h = tileWidth - 4; h >= tileWidth - 5; --h) { for (int v = 5; v < tileWidth - 5; ++v) { var N = RandomValue(); noiseArray[h + v * tileWidth] = N; noiseArray[(2 * tileWidth - 6 - h) + (tileWidth - 1 - v) * tileWidth] = N; } } // Top border Random.InitState((l & 4) == 0 ? 7654321 : 5647381); for (int h = 5; h <= tileWidth / 2; ++h) { var N = RandomValue(); noiseArray[h + (tileWidth - 3) * tileWidth] = N; noiseArray[(tileWidth - 1 - h) + (tileWidth - 3) * tileWidth] = N; } for (int v = tileWidth - 2; v < tileWidth; ++v) { for (int h = 5; h < tileWidth - 5; ++h) { var N = RandomValue(); noiseArray[h + v * tileWidth] = N; noiseArray[(tileWidth - 1 - h) + (2 * tileWidth - 6 - v) * tileWidth] = N; } } // Left border Random.InitState((l & 8) == 0 ? 7654321 : 5647381); for (int v = 5; v <= tileWidth / 2; ++v) { var N = RandomValue(); noiseArray[2 + v * tileWidth] = N; noiseArray[2 + (tileWidth - 1 - v) * tileWidth] = N; } for (int h = 1; h >= 0; --h) { for (int v = 5; v < tileWidth - 5; ++v) { var N = RandomValue(); noiseArray[h + v * tileWidth] = N; noiseArray[(4 - h) + (tileWidth - 1 - v) * tileWidth] = N; } } // Center Random.InitState(rand); for (int v = 5; v < tileWidth - 5; ++v) { for (int h = 5; h < tileWidth - 5; ++h) { var N = RandomValue(); noiseArray[h + v * tileWidth] = N; } } // Randomize for next texture rand = (rand * 1103515245 + 12345) & 0x7FFFFFFF; NoiseTextures[nl] = RTExtensions.CreateRTexture(new Vector2(tileWidth, tileWidth), 0, RenderTextureFormat.RHalf, FilterMode.Point, TextureWrapMode.Repeat); // Write data into render texture buffer.SetData(noiseArray); CBUtility.WriteIntoRenderTexture(NoiseTextures[nl], 1, buffer, GodManager.Instance.WriteData); buffer.ReleaseAndDisposeBuffer(); } }
protected override void Start() { base.Start(); m_mesh = MeshFactory.MakePlane(2, 2, MeshFactory.PLANE.XY, false); m_mesh.bounds = new Bounds(Vector3.zero, new Vector3(1e8f, 1e8f, 1e8f)); //The sky map is used to create a reflection of the sky for objects that need it (like the ocean) m_skyMap = new RenderTexture(512, 512, 0, RenderTextureFormat.ARGBHalf); m_skyMap.filterMode = FilterMode.Trilinear; m_skyMap.wrapMode = TextureWrapMode.Clamp; m_skyMap.anisoLevel = 9; m_skyMap.useMipMap = true; //m_skyMap.mipMapBias = -0.5f; m_skyMap.Create(); //Transmittance is responsible for the change in the sun color as it moves //The raw file is a 2D array of 32 bit floats with a range of 0 to 1 string path = Application.dataPath + m_filePath + "/transmittance.raw"; m_transmittance = new RenderTexture(TRANSMITTANCE_W, TRANSMITTANCE_H, 0, RenderTextureFormat.ARGBHalf); m_transmittance.wrapMode = TextureWrapMode.Clamp; m_transmittance.filterMode = FilterMode.Bilinear; m_transmittance.enableRandomWrite = true; m_transmittance.Create(); ComputeBuffer buffer = new ComputeBuffer(TRANSMITTANCE_W * TRANSMITTANCE_H, sizeof(float) * 3); CBUtility.WriteIntoRenderTexture(m_transmittance, 3, path, buffer, World.WriteData); buffer.Release(); //Iirradiance is responsible for the change in the sky color as the sun moves //The raw file is a 2D array of 32 bit floats with a range of 0 to 1 path = Application.dataPath + m_filePath + "/irradiance.raw"; m_irradiance = new RenderTexture(SKY_W, SKY_H, 0, RenderTextureFormat.ARGBHalf); m_irradiance.wrapMode = TextureWrapMode.Clamp; m_irradiance.filterMode = FilterMode.Bilinear; m_irradiance.enableRandomWrite = true; m_irradiance.Create(); buffer = new ComputeBuffer(SKY_W * SKY_H, sizeof(float) * 3); CBUtility.WriteIntoRenderTexture(m_irradiance, 3, path, buffer, World.WriteData); buffer.Release(); //Inscatter is responsible for the change in the sky color as the sun moves //The raw file is a 4D array of 32 bit floats with a range of 0 to 1.589844 //As there is not such thing as a 4D texture the data is packed into a 3D texture //and the shader manually performs the sample for the 4th dimension path = Application.dataPath + m_filePath + "/inscatter.raw"; m_inscatter = new RenderTexture(RES_MU_S * RES_NU, RES_MU, 0, RenderTextureFormat.ARGBHalf); m_inscatter.volumeDepth = RES_R; m_inscatter.wrapMode = TextureWrapMode.Clamp; m_inscatter.filterMode = FilterMode.Bilinear; m_inscatter.dimension = TextureDimension.Tex3D; m_inscatter.enableRandomWrite = true; m_inscatter.Create(); buffer = new ComputeBuffer(RES_MU_S * RES_NU * RES_MU * RES_R, sizeof(float) * 4); CBUtility.WriteIntoRenderTexture(m_inscatter, 4, path, buffer, World.WriteData); buffer.Release(); InitUniforms(m_skyMaterial); InitUniforms(m_skyMapMaterial); }