Closed martindevans closed 7 months ago
Hey @martindevans, you'll need to do a test to see what renderer is being used. Depending on the renderer you may need to flip the texture. You'll note that that is what the RiveScreen script also does.
A quick hack is just to flip the y scale on the mesh, as shown in the picture:
Alternatively, here is an updated script that shows how to flip the texture in a scriptable way depending on the backend used. Note that it also adjusts the pointer hit positions passed to Rive.
using System.Collections;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEditor;
using Rive;
using LoadAction = UnityEngine.Rendering.RenderBufferLoadAction;
using StoreAction = UnityEngine.Rendering.RenderBufferStoreAction;
//[ExecuteInEditMode]
public class RiveTexture : MonoBehaviour
{
public Rive.Asset asset;
public RenderTexture renderTexture;
public Fit fit = Fit.contain;
public Alignment alignment = Alignment.Center;
private Rive.RenderQueue m_renderQueue;
private Rive.Renderer m_riveRenderer;
private CommandBuffer m_commandBuffer;
private Rive.File m_file;
private Artboard m_artboard;
private StateMachine m_stateMachine;
private Camera m_camera;
private void Start()
{
var textureDescriptor = TextureHelper.Descriptor(0, 0);
renderTexture.enableRandomWrite = textureDescriptor.enableRandomWrite;
m_renderQueue = new Rive.RenderQueue(renderTexture);
m_riveRenderer = m_renderQueue.Renderer();
if (asset != null)
{
m_file = Rive.File.Load(asset);
m_artboard = m_file.Artboard(0);
m_stateMachine = m_artboard?.StateMachine();
}
if (m_artboard != null && renderTexture != null)
{
m_riveRenderer.Align(fit, alignment, m_artboard);
m_riveRenderer.Draw(m_artboard);
m_commandBuffer = m_riveRenderer.ToCommandBuffer();
m_commandBuffer.SetRenderTarget(renderTexture);
m_commandBuffer.ClearRenderTarget(true, true, UnityEngine.Color.clear, 0.0f);
m_riveRenderer.AddToCommandBuffer(m_commandBuffer);
m_camera = Camera.main;
if (m_camera != null)
{
Camera.main.AddCommandBuffer(CameraEvent.AfterEverything, m_commandBuffer);
}
}
FlipTexture();
}
private static bool flipY()
{
switch (UnityEngine.SystemInfo.graphicsDeviceType)
{
case UnityEngine.Rendering.GraphicsDeviceType.Metal:
case UnityEngine.Rendering.GraphicsDeviceType.Direct3D11:
return true;
default:
return false;
}
}
void FlipTexture()
{
if (!flipY()) return;
MeshRenderer meshRenderer = GetComponent<MeshRenderer>();
// Access the material of the MeshRenderer.
Material material = meshRenderer.material;
// Check if the material has a main texture.
if (material.mainTexture != null)
{
// Adjust the texture's UV mapping to flip it vertically.
material.mainTextureScale = new Vector2(1f, -1f); // Flip the texture vertically.
material.mainTextureOffset = new Vector2(0f, 1f); // Offset the texture to correct its position.
}
else
{
Debug.LogWarning("Material does not have a main texture set.", this);
}
}
private void Update()
{
HitTesting();
if (m_stateMachine != null)
{
m_stateMachine.Advance(Time.deltaTime);
}
}
bool m_wasMouseDown = false;
private Vector2 m_lastMousePosition;
void HitTesting()
{
Camera camera = Camera.main;
if (camera == null || renderTexture == null || m_artboard == null) return;
if (!Physics.Raycast(camera.ScreenPointToRay(Input.mousePosition), out RaycastHit hit))
return;
UnityEngine.Renderer rend = hit.transform.GetComponent<UnityEngine.Renderer>();
MeshCollider meshCollider = hit.collider as MeshCollider;
if (rend == null || rend.sharedMaterial == null || rend.sharedMaterial.mainTexture == null || meshCollider == null)
return;
Vector2 pixelUV = flipY() ? new Vector2(hit.textureCoord.x, 1 - hit.textureCoord.y) : hit.textureCoord;
pixelUV.x *= renderTexture.width;
pixelUV.y *= renderTexture.height;
Vector3 mousePos = camera.ScreenToViewportPoint(Input.mousePosition);
Vector2 mouseRiveScreenPos = new(mousePos.x * camera.pixelWidth, (1 - mousePos.y) * camera.pixelHeight);
var rect = new Rect(0, 0, renderTexture.width, renderTexture.height);
if (m_lastMousePosition != mouseRiveScreenPos || transform.hasChanged)
{
Vector2 local = m_artboard.LocalCoordinate(pixelUV, rect, fit, alignment);
m_stateMachine?.PointerMove(local);
m_lastMousePosition = mouseRiveScreenPos;
}
if (Input.GetMouseButtonDown(0))
{
Vector2 local = m_artboard.LocalCoordinate(pixelUV, rect, fit, alignment);
m_stateMachine?.PointerDown(local);
m_wasMouseDown = true;
}
else if (m_wasMouseDown)
{
m_wasMouseDown = false; Vector2 local = m_artboard.LocalCoordinate(pixelUV, rect, fit, alignment);
m_stateMachine?.PointerUp(local);
}
}
private void OnDisable()
{
if (m_camera != null && m_commandBuffer != null)
{
m_camera.RemoveCommandBuffer(CameraEvent.AfterEverything, m_commandBuffer);
}
}
}
Long term we should expose a Rive component that takes care of that all for you, but we're still working on other edge cases.
Thanks for confirming that, I was worried I'd made some stupid setup mistake!
The script doesn't quite work for me since I'm using a canvas image rather than a mesh renderer, but I get the idea.
For anyone else using Canvas, you can flip the RawImage this way:
private void FlipTexture()
{
// Check if the texture needs to be flipped based on the graphics API
if (ShouldFlipTexture())
{
rawImage.uvRect = new Rect(0, 1, 1, -1); // Flip the texture by adjusting the UV Rect
}
}
/// <summary>
/// Determines if the texture should be flipped based on the graphics API.
/// </summary>
/// <returns></returns>
private static bool ShouldFlipTexture()
{
switch (SystemInfo.graphicsDeviceType)
{
case GraphicsDeviceType.Metal:
case GraphicsDeviceType.Direct3D11:
return true;
default:
return false;
}
}
Note that if you're passing pointer input to Rive, you might also need to account for the image being flipped and invert the pointer values as well.
I've set up a very basic scene, rendering a Rive file (this one) into a texture, and then rendering the texture to a UI RawImage element.
However, as you can see here the image is incorrectly oriented:
Is this a setup mistake on my end? I've basically just copy+pasted the example code!