Exemple #1
0
        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();
        }