override public void GenerateHeightField(int currentFrame, ExtendedHeightField extendedHeightField) { Profiler.BeginSample("Clear Height Field"); extendedHeightField.Clear(); Profiler.EndSample(); Profiler.BeginSample("Set Point Map"); waveParticles.setPointMap(currentFrame, ref pointMap); Profiler.EndSample(); Profiler.BeginSample("Convolve Wave Particles"); for (int row = 0; row < heightFieldInfo.VertRes; row++) { for (int col = 0; col < heightFieldInfo.HoriRes; col++) { int index = row * heightFieldInfo.HoriRes + col; for (int y = 0; y < kernelHeight; y++) { for (int x = 0; x < kernelWidth; x++) { int y_index = (y - (kernelHeight / 2)) + row; int x_index = (x - (kernelWidth / 2)) + col; if (y_index > 0 && y_index < heightFieldInfo.VertRes && x_index > 0 && x_index < heightFieldInfo.HoriRes) { int fresh_index = (y_index * heightFieldInfo.HoriRes) + (x_index); extendedHeightField.heightMap[index] += (Color)(pointMap.heightMap[fresh_index] * kernel[(y * kernelWidth) + x]); } } } } } extendedHeightField.ApplyCPUHeightMap(); Profiler.EndSample(); }
override public void Initialise(ExtendedHeightField.HeightFieldInfo hf, ParticleContainer wp) { heightFieldInfo = hf; pointMap = new ExtendedHeightField(hf.Width, hf.Height, hf.HoriRes, hf.VertRes); pointMap.textureHeightMap.name = "Point Map Texture"; waveParticles = wp; kernelWidth = Mathf.CeilToInt((WaveParticle.RADIUS / heightFieldInfo.Width) * heightFieldInfo.HoriRes); kernelHeight = Mathf.CeilToInt((WaveParticle.RADIUS / heightFieldInfo.Height) * heightFieldInfo.VertRes); kernel = creatKernel(kernelWidth, kernelHeight, heightFieldInfo); }
override public void GenerateHeightField(int currentFrame, ExtendedHeightField extendedHeightField) { Profiler.BeginSample("Clear Height Field"); extendedHeightField.Clear(); Profiler.EndSample(); Profiler.BeginSample("Set Point Map"); waveParticles.setPointMap(currentFrame, ref pointMap); Profiler.EndSample(); Profiler.BeginSample("Convolve Wave Particles"); convolveWaveParticles(); extendedHeightField.UpdateTexture(convolvedTexture); Profiler.EndSample(); }
override public void GenerateHeightField(int currentFrame, ExtendedHeightField extendedHeightField) { extendedHeightField.Clear(); foreach (WaveParticle waveParticle in waveParticles) { Vector2 waveParticlePosition = waveParticle.getPosition(currentFrame); int xPos = Mathf.RoundToInt((waveParticlePosition.x / heightFieldInfo.Width) * heightFieldInfo.HoriRes); int yPos = Mathf.RoundToInt((waveParticlePosition.y / heightFieldInfo.Height) * heightFieldInfo.VertRes); for (int y = 0; y < sectionWidth; y++) { for (int x = 0; x < sectionHeight; x++) { int col = (x - (sectionWidth / 2)) + xPos; int row = (y - (sectionHeight / 2)) + yPos; if (row > 0 && row < heightFieldInfo.VertRes && col > 0 && col < heightFieldInfo.HoriRes) { int index = row * heightFieldInfo.HoriRes + col; Vector2 position = new Vector2(heightFieldInfo.UnitX * col, heightFieldInfo.UnitY * row); Vector2 diff = position - waveParticlePosition; float abs_diff = diff.magnitude; if (abs_diff > WaveParticle.RADIUS) { // Don't need to do rest of calculation based on rectangle function. continue; } // Caclulate vertical displacement float piOverRadius = Mathf.PI / WaveParticle.RADIUS; float y_displacement = (waveParticle.amplitude * 0.5f) * (Mathf.Cos(abs_diff * piOverRadius) + 1); Vector2 longitudinalComponent; { float dotproduct = Vector2.Dot(waveParticle.velocity.normalized, diff); Vector2 Li = -Mathf.Sin(dotproduct * piOverRadius) * waveParticle.velocity.normalized; longitudinalComponent = y_displacement * Li; } float x_displacement = longitudinalComponent.x; float z_displacement = longitudinalComponent.y; extendedHeightField.heightMap[index] += new Color(x_displacement, y_displacement, z_displacement, 1f); } } } } }
public WaveParticleSystem(float particleSpeed, float particleRadius, int maxNumParticles, int horRes, int vertRes, float height, float width, float waveParticleKillThreshold) { _particleSpeed = particleSpeed; _particleRadius = particleRadius; _numParticles = maxNumParticles; _waveParticleKillThreshold = waveParticleKillThreshold; _currentFrame = 0; // TODO: move all relvant code to do with this to here! _frameCycleLength = WaveParticle.FRAME_CYCLE_LENGTH; _extendedHeightField = new ExtendedHeightField(width, height, horRes, vertRes); _extendedHeightField.Clear(); _particleContainer = SplatEnumToInstance(_splatImplementationChoice); _particleContainer.Initialise(maxNumParticles, waveParticleKillThreshold); _heightFieldGenerator = ConvEnumToInstance(_convolutionImplementationChoice); _heightFieldGenerator.Initialise(_extendedHeightField.heightFieldInfo, _particleContainer); }
override public void Initialise(ExtendedHeightField.HeightFieldInfo hf, ParticleContainer wp) { heightFieldInfo = hf; pointMap = new ExtendedHeightField(hf.Width, hf.Height, hf.HoriRes, hf.VertRes); convolvedTexture = new Texture2D(heightFieldInfo.HoriRes, heightFieldInfo.VertRes, TextureFormat.RGBAFloat, false); convolvedTexture.anisoLevel = 1; convolvedTexture.filterMode = FilterMode.Point; convolvedTexture.wrapMode = TextureWrapMode.Clamp; convolvedTexture.name = "Convolved Texture"; shaderTexture = new RenderTexture(heightFieldInfo.HoriRes, heightFieldInfo.VertRes, 24, RenderTextureFormat.ARGBFloat); shaderTexture.antiAliasing = 1; shaderTexture.anisoLevel = 0; shaderTexture.autoGenerateMips = false; shaderTexture.wrapMode = TextureWrapMode.Clamp; shaderTexture.filterMode = FilterMode.Point; int kernelWidth = Mathf.CeilToInt((WaveParticle.RADIUS / heightFieldInfo.Width) * heightFieldInfo.HoriRes); int kernelHeight = Mathf.CeilToInt((WaveParticle.RADIUS / heightFieldInfo.Height) * heightFieldInfo.VertRes); Color[] kernelArray = Convolution2DFastHeightFieldGenerator.creatKernel(kernelHeight, kernelWidth, heightFieldInfo); kernel = new Texture2D(kernelWidth, kernelHeight, TextureFormat.RGBAFloat, false); kernel.SetPixels(kernelArray); kernel.Apply(); convolutionMaterial = new Material(Shader.Find("Unlit/2DFunction")); convolutionMaterial.SetTexture(Shader.PropertyToID("_KernelTex"), kernel); convolutionMaterial.SetFloat(Shader.PropertyToID("_Width"), heightFieldInfo.Width); convolutionMaterial.SetFloat(Shader.PropertyToID("_Height"), heightFieldInfo.Height); convolutionMaterial.SetInt(Shader.PropertyToID("_HoriRes"), heightFieldInfo.HoriRes); convolutionMaterial.SetInt(Shader.PropertyToID("_VertRes"), heightFieldInfo.VertRes); convolutionMaterial.SetFloat(Shader.PropertyToID("_ParticleRadii"), WaveParticle.RADIUS); convolutionMaterial.SetFloat(Shader.PropertyToID("_KernelWidth"), kernelWidth); convolutionMaterial.SetFloat(Shader.PropertyToID("_KernelHeight"), kernelHeight); waveParticles = wp; }
void Start() { waterMaterial = GetComponent <Renderer>().material; waveParticles.Initialise(numWaveParticles, waveParticleKillThreshold); { int horRes = 100; int vertRes = 100; float height = 8; float width = 8; extendedHeightField = new ExtendedHeightField(width, height, horRes, vertRes); extendedHeightField.Clear(); } _mesh = GetComponent <MeshFilter>().mesh; vertices = new Vector3[extendedHeightField.HoriRes * extendedHeightField.VertRes]; uv = new Vector2[extendedHeightField.HoriRes * extendedHeightField.VertRes]; triangles = new int[(extendedHeightField.HoriRes - 1) * (extendedHeightField.VertRes - 1) * 6]; heightFieldGenerator = HeightFieldGeneratorSelector.CreateAndInitialise(selectedHeightFieldGenerator, extendedHeightField.heightFieldInfo, waveParticles); // Initialise and set-up the mesh the wave particles will be rendered to { GenerateMeshFromHeightMap(extendedHeightField, vertices, uv, triangles, _mesh); Renderer rend = GetComponent <Renderer>(); if (rend != null) { rend.material = waterMaterial; waterMaterial.SetTexture(Shader.PropertyToID("_MainTex"), extendedHeightField.textureHeightMap); waterMaterial.SetFloat(Shader.PropertyToID("_UnitX"), extendedHeightField.UnitX); waterMaterial.SetFloat(Shader.PropertyToID("_UnitY"), extendedHeightField.UnitY); waterMaterial.SetFloat(Shader.PropertyToID("_HoriResInverse"), 1f / ((float)extendedHeightField.HoriRes)); waterMaterial.SetFloat(Shader.PropertyToID("_VertResInverse"), 1f / ((float)extendedHeightField.VertRes)); waterMaterial.SetInt(Shader.PropertyToID("_VertexEnabled"), _useGpuForVertices ? 1 : 0); } } _hasStarted = true; }
void GenerateMeshFromHeightMap(ExtendedHeightField heightMap, Vector3[] verticesOut, Vector2[] uvOut, int[] trianglesOut, Mesh mesh) { if (needFreshMesh) { if (!_useGpuForVertices) { for (int row = 0; row < heightMap.VertRes; row++) { for (int col = 0; col < heightMap.HoriRes; col++) { int index = row * heightMap.HoriRes + col; Vector4 displacement = heightMap.heightMap[index]; verticesOut[index].x = (col * heightMap.UnitX + displacement.x) - (0.5f * heightMap.Width); verticesOut[index].y = displacement.y; verticesOut[index].z = (row * heightMap.UnitY + displacement.z) - (0.5f * heightMap.Height); uvOut[index].x = (col * heightMap.UnitX + displacement.x) / heightMap.Width; uvOut[index].y = (row * heightMap.UnitY + displacement.z) / heightMap.Height; } } } else { for (int row = 0; row < heightMap.VertRes; row++) { for (int col = 0; col < heightMap.HoriRes; col++) { int index = row * heightMap.HoriRes + col; verticesOut[index].x = (col * heightMap.UnitX) - (0.5f * heightMap.Width); verticesOut[index].y = 0; verticesOut[index].z = (row * heightMap.UnitY) - (0.5f * heightMap.Height); uvOut[index].x = (col * heightMap.UnitX) / heightMap.Width; uvOut[index].y = (row * heightMap.UnitY) / heightMap.Height; } } } { int triangle_index = 0; for (int row = 0; row < heightMap.VertRes - 1; row++) { for (int col = 0; col < heightMap.HoriRes - 1; col++) { int vertIndex = row * heightMap.HoriRes + col; trianglesOut[triangle_index++] = vertIndex; trianglesOut[triangle_index++] = vertIndex + heightMap.HoriRes; trianglesOut[triangle_index++] = vertIndex + heightMap.HoriRes + 1; trianglesOut[triangle_index++] = vertIndex; trianglesOut[triangle_index++] = vertIndex + heightMap.HoriRes + 1; trianglesOut[triangle_index++] = vertIndex + 1; } } } } mesh.Clear(); mesh.vertices = vertices; mesh.uv = uv; mesh.triangles = triangles; mesh.RecalculateBounds(); mesh.RecalculateNormals(); }
public abstract void GenerateHeightField(int currentFrame, ExtendedHeightField extendedHeightField);
public void setPointMap(int currentFrame, ref ExtendedHeightField pointMap) { bool antiAliased = false; Profiler.BeginSample("Clear Point Map"); pointMap.Clear(); Profiler.EndSample(); Profiler.BeginSample("Get Point Map Raw"); var pointMapRaw = pointMap.heightMap; Profiler.EndSample(); Profiler.BeginSample("Get Height Field Info"); var heightFieldInfo = pointMap.heightFieldInfo; Profiler.EndSample(); Profiler.BeginSample("For Each Wave Particle"); foreach (var waveParticle in this) { Profiler.BeginSample("Splat Wave Particle"); if (antiAliased) { Vector2 waveParticlePosition = waveParticle.getPosition(currentFrame); float xpos = (waveParticlePosition.x / heightFieldInfo.Width) * heightFieldInfo.HoriRes; float ypos = (waveParticlePosition.y / heightFieldInfo.Height) * heightFieldInfo.VertRes; int col0; int col1; int row0; int row1; { int col = Mathf.RoundToInt(xpos); int row = Mathf.RoundToInt(ypos); col0 = col - 1; row0 = row - 1; col1 = col; row1 = row; } float width0 = 0.5f + col1 - xpos; float width1 = 0.5f + xpos - col1; float height0 = 0.5f + row1 - ypos; float height1 = 0.5f + ypos - row1; bool col0InRange = col0 < heightFieldInfo.HoriRes && col0 > 0; bool col1InRange = col1 < heightFieldInfo.HoriRes && col1 > 0; bool row0InRange = row0 < heightFieldInfo.VertRes && row0 > 0; bool row1InRange = row1 < heightFieldInfo.VertRes && row1 > 0; if (col0InRange && row0InRange) { pointMapRaw[(row0 * heightFieldInfo.HoriRes) + col0].g += waveParticle.amplitude * width0 * height0; } if (col1InRange && row0InRange) { pointMapRaw[(row0 * heightFieldInfo.HoriRes) + col1].g += waveParticle.amplitude * width1 * height0; } if (col0InRange && row1InRange) { pointMapRaw[(row1 * heightFieldInfo.HoriRes) + col0].g += waveParticle.amplitude * width0 * height1; } if (col1InRange && row1InRange) { pointMapRaw[(row1 * heightFieldInfo.HoriRes) + col1].g += waveParticle.amplitude * width1 * height1; } } else { Vector2 waveParticlePosition = waveParticle.getPosition(currentFrame); int xPos = Mathf.RoundToInt((waveParticlePosition.x / heightFieldInfo.Width) * heightFieldInfo.HoriRes); int yPos = Mathf.RoundToInt((waveParticlePosition.y / heightFieldInfo.Height) * heightFieldInfo.VertRes); int index = (yPos * heightFieldInfo.HoriRes) + xPos; if (xPos < heightFieldInfo.HoriRes && xPos > 0 && yPos < heightFieldInfo.VertRes && yPos > 0) { pointMapRaw[index].g += waveParticle.amplitude; } } Profiler.EndSample(); } Profiler.EndSample(); Profiler.BeginSample("Apply CPU Height Map"); pointMap.ApplyCPUHeightMap(); Profiler.EndSample(); }
public override void GenerateHeightField(int currentFrame, ExtendedHeightField extendedHeightField) { return; }
public void setPointMap(int currentFrame, ref ExtendedHeightField pointMap) { Profiler.BeginSample("Set Point Map Internal"); Profiler.BeginSample("Initialisation"); /// /// Initialise _splatTexture if it hasn't been yet. /// if (_splatTexture == null) { if (antiAliased == AntiAlias.SCALE) { _splatTexture = new RenderTexture(pointMap.HoriRes * antiAliasFactor, pointMap.VertRes * antiAliasFactor, 24, RenderTextureFormat.ARGBFloat); } else { _splatTexture = new RenderTexture(pointMap.HoriRes, pointMap.VertRes, 24, RenderTextureFormat.ARGBFloat); } _splatTexture.enableRandomWrite = true; } if (!_splatTexture.IsCreated()) { _splatTexture.Create(); } Profiler.EndSample(); Profiler.BeginSample("Intitialise Splatter"); /// /// Initialise the SplatParticles GPU Compute Kernel to splat the particles to a texture /// _gpuSplatParticles.SetTexture(kernel_SplatParticles, SPLAT_TEXTURE, _splatTexture); _gpuSplatParticles.SetBuffer(kernel_SplatParticles, WAVE_PARTICLE_BUFFER, _waveParticlesBuffer); _gpuSplatParticles.SetFloat(FIXED_DELTA_TIME, Time.fixedDeltaTime); _gpuSplatParticles.SetInt(CURRENT_FRAME, currentFrame); _gpuSplatParticles.SetFloat(PARTICLE_SPEED, WaveParticle.PARTICLE_SPEED); _gpuSplatParticles.SetInt(HORI_RES, pointMap.HoriRes); _gpuSplatParticles.SetInt(VERT_RES, pointMap.VertRes); _gpuSplatParticles.SetFloat(PLANE_WIDTH, pointMap.Width); _gpuSplatParticles.SetFloat(PLANE_HEIGHT, pointMap.Height); _gpuSplatParticles.SetInt(ANTI_ALIASED, (int)antiAliased); _gpuSplatParticles.SetInt(ANTI_ALIAS_FACTOR, antiAliasFactor); /// /// Dispatch the kernel that splats wave particles to the _splatTexture /// _gpuSplatParticles.Dispatch(kernel_SplatParticles, ((int)_particleContainerSize) / THREAD_GROUPS_X, 1, 1); Profiler.EndSample(); Profiler.BeginSample("Do the splatting"); if (antiAliased == AntiAlias.SCALE) { /// /// As we have SCALE anti-aliasing, we need to downscale the texture to a new one. /// downsampleMaterial.SetInt(DOWNSAMPLE_ANTI_ALIAS_FACTOR_ID, antiAliasFactor); downsampleMaterial.SetInt(DOWNSAMPLE_TEXTURE_WIDTH_ID, pointMap.HoriRes); downsampleMaterial.SetInt(DOWNSAMPLE_TEXTURE_HEIGHT_ID, pointMap.VertRes); if (outputTexture == null || downscaleRenderTexture == null) { pointMap.InitialiseTexture(out outputTexture, name: "Downscale Output Texture"); // Set the texture to the active one so that it's values can be read back out to the pointMapTexture downscaleRenderTexture = new RenderTexture(pointMap.HoriRes, pointMap.VertRes, 24, RenderTextureFormat.ARGBFloat); } if (!downscaleRenderTexture.IsCreated()) { downscaleRenderTexture.Create(); } RenderTexture.active = downscaleRenderTexture; GL.Clear(true, true, Color.black); // Blit what is stored in the _splatTexture to downscaleRenderTexture Graphics.Blit(_splatTexture, downscaleRenderTexture, downsampleMaterial); // Read back values from the render texture outputTexture.ReadPixels(new Rect(0, 0, outputTexture.width, outputTexture.height), 0, 0, false); outputTexture.Apply(); RenderTexture.active = _splatTexture; downscaleRenderTexture.Release(); GL.Clear(true, true, Color.black); RenderTexture.active = null; pointMap.UpdateTexture(outputTexture); } else { // Copy RenderTexture to a Texture2D RenderTexture.active = _splatTexture; if (outputTexture == null) { pointMap.InitialiseTexture(out outputTexture, name: "Point Map Texture"); } // Read back values from the render texture outputTexture.ReadPixels(new Rect(0, 0, outputTexture.width, outputTexture.height), 0, 0, false); outputTexture.Apply(); pointMap.UpdateTexture(outputTexture); GL.Clear(true, true, Color.black); RenderTexture.active = null; } Profiler.EndSample(); Profiler.EndSample(); }