0
\$\begingroup\$

I am using this neat Unity demo I found on Stack Overflow, which demonstrates texture masking via RenderTexture:

Can you erase a texture in real time in Unity

But the mapping from mouse position to world space is wrong. This is the script that does the mapping:

using UnityEngine;
using System.Collections;

public class MaskCamera : MonoBehaviour
{
    public Material EraserMaterial;
    private bool firstFrame;
    private Vector2? newHolePosition;

    private void CutHole(Vector2 imageSize, Vector2 imageLocalPosition)
    {
        Rect textureRect = new Rect(0.0f, 0.0f, 1.0f, 1.0f);
        Rect positionRect = new Rect(
            (imageLocalPosition.x - 0.5f * EraserMaterial.mainTexture.width) / imageSize.x,
            (imageLocalPosition.y - 0.5f * EraserMaterial.mainTexture.height) / imageSize.y,
            EraserMaterial.mainTexture.width / imageSize.x,
            EraserMaterial.mainTexture.height / imageSize.y
        );
        GL.PushMatrix();
        GL.LoadOrtho();
        for (int i = 0; i < EraserMaterial.passCount; i++)
        {
            EraserMaterial.SetPass(i);
            GL.Begin(GL.QUADS);
            GL.Color(Color.white);
            GL.TexCoord2(textureRect.xMin, textureRect.yMax);
            GL.Vertex3(positionRect.xMin, positionRect.yMax, 0.0f);
            GL.TexCoord2(textureRect.xMax, textureRect.yMax);
            GL.Vertex3(positionRect.xMax, positionRect.yMax, 0.0f);
            GL.TexCoord2(textureRect.xMax, textureRect.yMin);
            GL.Vertex3(positionRect.xMax, positionRect.yMin, 0.0f);
            GL.TexCoord2(textureRect.xMin, textureRect.yMin);
            GL.Vertex3(positionRect.xMin, positionRect.yMin, 0.0f);
            GL.End();
        }
        GL.PopMatrix();
    }

    public void Start()
    {
        firstFrame = true;
    }

    public void Update()
    {
        newHolePosition = null;
        if (Input.GetMouseButton(0))
        {
            Vector2 v = camera.ScreenToWorldPoint(Input.mousePosition);
            Rect worldRect = new Rect(-8.0f, -6.0f, 16.0f, 12.0f);
            if (worldRect.Contains(v))
                newHolePosition = new Vector2(1600 * (v.x - worldRect.xMin) / worldRect.width, 1200 * (v.y - worldRect.yMin) / worldRect.height);
        }
    }

    public void OnPostRender()
    {
        if (firstFrame)
        {
            firstFrame = false;
            GL.Clear(false, true, new Color(0.0f, 0.0f, 0.0f, 0.0f));
        }
        if (newHolePosition != null)
            CutHole(new Vector2(1600.0f, 1200.0f), newHolePosition.Value);
    }
}

I fixed line 49 and 50 like so:

Vector2 v = GetComponent<Camera>().ScreenToWorldPoint(Input.mousePosition);
Rect worldRect = new Rect(0.0f, 0.0f, 16.0f, 12.0f);

So the script compiles and the worldRect is in the right place now. Through debugging I found that the world coordinates returned on line 49 are off. I also tried setting the z value of mousePosition to 10, even though the cameras are orthographic, like so:

Vector3 mousePos = Input.mousePosition;
mousePos.z = 10;
Vector2 v = GetComponent<Camera>().ScreenToWorldPoint(mousePos);

The mapping from the mouse to worldspace is still wrong though. Mouse coordinates within a small rectangle near the center are mapping to the full width and height of the image in world space.

\$\endgroup\$
1
\$\begingroup\$

Ack! Okay, so the camera in the original script is referring to the Main Camera, not the camera with the script attached. Line 49 should read as follows:

Vector2 v = Camera.main.ScreenToWorldPoint(Input.mousePosition);

No other changes were necessary.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.