public void ApplyBrush(Vector3 hitPoint) { if (CurrentTexture == null) { Debug.Log("You haven't created a texture for the current mode yet."); return; } RaycastHit hit; Vector2 texForward, texRight; if (!GrassManipulationUtility.GetWorldToTextureSpaceMatrix(new Ray(hitPoint + Vector3.up * 1000, Vector3.down), Epsilon, GrassColliders, out hit, out texForward, out texRight)) { return; } Vector2 texCoord = hit.textureCoord; //Convert the world space radius to a pixel radius in texture space. This requires square textures. int pixelRadius = (int)(Size * texForward.magnitude * CurrentTexture.width); //Calculate the pixel coordinates of the point where the raycast hit the texture. Vector2 mid = new Vector2(texCoord.x * CurrentTexture.width, texCoord.y * CurrentTexture.height); //Calculate the pixel area where the texture will be changed int targetStartX = (int)(mid.x - pixelRadius); int targetStartY = (int)(mid.y - pixelRadius); int startX = Mathf.Clamp(targetStartX, 0, CurrentTexture.width); int startY = Mathf.Clamp(targetStartY, 0, CurrentTexture.height); int width = Mathf.Min(targetStartX + pixelRadius * 2, CurrentTexture.width) - targetStartX; int height = Mathf.Min(targetStartY + pixelRadius * 2, CurrentTexture.height) - targetStartY; mid -= new Vector2(startX, startY); //Get pixels Color[] pixels = CurrentTexture.GetPixels(startX, startY, width, height); //Iterate trough all pixels for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { int index = y * width + x; Vector2 uv = ((new Vector2(x, y) - mid) / pixelRadius) * 0.5f + new Vector2(0.5f, 0.5f); pixels[index] = ApplyBrushToPixel(pixels[index], uv); } } //Save pixels and apply them to the texture CurrentTexture.SetPixels(startX, startY, width, height, pixels); CurrentTexture.Apply(); }
private void RoundDisplacement() { Vector2 texCoord, texForward, texRight, inverseTexForward, inverseTexRight; Vector3 rayOrigin = transform.TransformPoint(offset); Transform target = GrassManipulationUtility.GetWorldToTextureSpaceMatrix(rayOrigin, rayDirection, maxDistance, 0.1f, grassLayer, out texCoord, out texForward, out texRight); if (target == null) { return; } //Get texture of grass object var tex = GrassManipulationUtility.GetGrassTexture(target, false); //Invert the 2x2 world to texture space matrix. GrassManipulationUtility.Invert2x2Matrix(texForward, texRight, out inverseTexForward, out inverseTexRight); inverseTexForward.Normalize(); inverseTexRight.Normalize(); //Convert the world space radius to a pixel radius in texture space. This requires square textures. int pixelRadius = (int)(radius * texForward.magnitude * tex.width); //Calculate the pixel coordinates of the point where the raycast hit the texture. Vector2 mid = new Vector2(texCoord.x * tex.width, texCoord.y * tex.height); //Calculate the pixel area where the texture will be changed int targetX = (int)(mid.x - pixelRadius); int targetY = (int)(mid.y - pixelRadius); int rectX = Mathf.Clamp(targetX, 0, tex.width); int rectY = Mathf.Clamp(targetY, 0, tex.height); int width = Mathf.Min(targetX + pixelRadius * 2, tex.width) - targetX; int height = Mathf.Min(targetY + pixelRadius * 2, tex.height) - targetY; mid -= new Vector2(rectX, rectY); //Get pixels Color[] pixels = tex.GetPixels(rectX, rectY, width, height); Vector3 forward = transform.forward; //Iterate trough all pixels for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { var pixel = pixels[x + y * width]; Vector2 dir = (new Vector2(x, y) - mid) / pixelRadius; //Texture space to world space dir = dir.x * inverseTexRight + dir.y * inverseTexForward; float pressure = 1 - pressureStrength * CalcFalloff(dir.magnitude, pressureFalloff); //Check angle and pressure threshold Vector2 characterForward = new Vector2(forward.x, forward.z); if (pixel.b > pressureThreshold && Vector2.Angle(dir, characterForward) < maxAngle) { Vector2 displacementDir; if (directionalDisplacement) { var temp = transform.position - lastPosition; displacementDir = new Vector2(temp.x, temp.z); } else { displacementDir = dir; } float falloff = CalcFalloff(dir.magnitude, displacementFalloff); //Falloff and strength dir = displacementDir.normalized * falloff * displacementStrength; //To color space dir = GrassManipulationUtility.VectorToColorSpace(dir); Color newColor = new Color(dir.x, dir.y, pressure, 1); //Adds the new color to the pixel array pixels[x + y * width] = blendChanges ? Color.Lerp(pixels[x + y * width], newColor, Time.deltaTime * blendSpeed) : newColor; } } } //Save pixels and apply them to the texture tex.SetPixels(rectX, rectY, width, height, pixels); //Search for texture updater, which prevents multiply applys per frame (for multiple displacers) TextureUpdater updater = target.GetComponent <TextureUpdater>(); if (updater == null) { updater = target.gameObject.AddComponent <TextureUpdater>(); updater.targetTexture = tex; } updater.RequestTextureUpdate(); }