5
\$\begingroup\$

I am trying to show multiple images on a grid system which are randomly generated and the grid is moving from right to left.

What my client wants is when a part of a picture goes off the left edge of the viewport, it should start to peek in from the right, similar to the image shown below:

Diagram of coloured squares. Squares that are cut off by the left edge of the view correspond to edges of squares visible on the right edge

You can see the red and blue images each represent the same object. When they go off the left edge of the screen, they appear the right edge. It should happen seamlessly, without a sudden "pop" appearing out of nowhere.

I think it can be done via a shader, but I'm not a shader programmer. How can I achieve this effect?

\$\endgroup\$
8
  • \$\begingroup\$ I don't think it can be done via shader \$\endgroup\$
    – Ocelot
    Commented Jul 9, 2019 at 10:22
  • \$\begingroup\$ Then how can I do it? \$\endgroup\$
    – Saad Anees
    Commented Jul 9, 2019 at 12:25
  • \$\begingroup\$ Drawing object twice when it overlaps the border, offsetting it by the screen width or height \$\endgroup\$
    – Ocelot
    Commented Jul 9, 2019 at 13:11
  • \$\begingroup\$ @Ocelot Thats what im doing. But i dont want that because its not seamless \$\endgroup\$
    – Saad Anees
    Commented Aug 20, 2019 at 11:46
  • \$\begingroup\$ I notice you've added a bounty on this question to attract further answer activity. Is there anything specific missing or off-target about the existing answers, that edits or nee answers could focus on addressing to better meet your needs? \$\endgroup\$
    – DMGregory
    Commented Aug 20, 2019 at 18:14

2 Answers 2

6
+25
\$\begingroup\$

You can do this with magic (shader)!

Secret: Cutting Assistant In Half

Of course, we know she is never actually cut in half. So, there has to be some logical explanation for it all. Well, he certainly relies on the help of an assistant alright. But it’s not one – he has two of them!

https://www.editorchoice.com/magic-tricks-revealed/

as you see in the below picture we need two persons or objects to achieve this effect.

enter image description here

you can achieve this effect easily by using world space shader that I explained before I did this with childing twin but you can use code to teleport.

enter image description here enter image description here

enter image description here

Shader "Smkgames/worldSpaceFade" {
    Properties {
         _Size("Size",Vector) = (2,0,2,0)
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
         _BumpMap ("Bumpmap", 2D) = "bump" {}
        _Glossiness ("Smoothness", Range(0,1)) = 0.5
        _Metallic ("Metallic", Range(0,1)) = 0.0
    }
    SubShader {
 Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
     Pass {
        ZWrite On
        ColorMask 0
    }
        LOD 200

        CGPROGRAM
        #pragma surface surf Standard fullforwardshadows alpha:fade

        #pragma target 3.0

        sampler2D _MainTex,_BumpMap;

        struct Input {
            float2 uv_MainTex;
            float2 uv_BumpMap;
            float3 worldPos: TEXCOORD2;
        };

        half _Glossiness;
        half _Metallic;
        fixed4 _Color;
        float4 _Size;

        void vert (inout appdata_full v, out Input o){
            UNITY_INITIALIZE_OUTPUT(Input,o);
            o.worldPos = mul(unity_ObjectToWorld, v.vertex);
        }


        UNITY_INSTANCING_BUFFER_START(Props)
        UNITY_INSTANCING_BUFFER_END(Props)

        void surf (Input IN, inout SurfaceOutputStandard o) {
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
            float4 equation = (IN.worldPos.x/_Size.x)*(IN.worldPos.x/_Size.x);
            float4 InvertEquation = (IN.worldPos.z/_Size.z)*(IN.worldPos.z/_Size.z);
            float4 finalEquiation = max(equation,InvertEquation);
            o.Albedo = c.rgb;
            o.Metallic = _Metallic;
            o.Smoothness = _Glossiness;
            o.Alpha = step(finalEquiation,0.5);
             o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap));
        }
        ENDCG
    }
    FallBack "Diffuse"
}

Object Pooling Concept

another concept that you should know is Object Pooling. when one person or object arrived to the destination then move it back to the first position and her twin will appears.

enter image description here

Dynamic Teleport

better way is Teleporting by code:

enter image description here

using UnityEngine;

public class Teleport : MonoBehaviour
{
public Transform teleportTarget;
private void OnTriggerEnter(Collider other) {
    var pos = other.transform.position;
    pos.x = teleportTarget.position.x;
    other.transform.position = pos;
}
}
\$\endgroup\$
3
  • 1
    \$\begingroup\$ The shader is redundant if the view is going to hide the fade anyway. \$\endgroup\$
    – Ocelot
    Commented Aug 22, 2019 at 21:56
  • \$\begingroup\$ @Ocelot what do you mean? \$\endgroup\$ Commented Aug 23, 2019 at 3:21
  • 1
    \$\begingroup\$ I think what Ocelot means is that in OP's case, the camera crops the player's view, so they can't see the left edge of the object passing out of the looped area, nor the right edge of the object passing into the looped area. So, there's no need to use a shader to fade/clip these parts - they're already safely hidden off-screen. \$\endgroup\$
    – DMGregory
    Commented Aug 26, 2019 at 15:56
3
\$\begingroup\$

Myself, I wouldn't do this with a shader, but with a second camera.

The idea is we'll take our original/main/central camera, and make a copy that butts-up perfectly against its left side. As an object exits the left side of our main camera's view, it will enter the right side of this camera's view. If we draw both cameras to the same output buffer (the player's screen/window), then we'll see two images of the object: one exiting to the left, and one entering from the right.

All it takes is a little coordination to make sure the alignment is perfect.

To keep things simple, I'm going to make some assumptions:

  • Your central camera is...
    • orthographic
    • located at world x = 0
    • in default orientation (looking along the z+ axis, with y+ up)
    • unchanging over time (you're not modifying its location or parameters)
  • Your game window doesn't change size / mobile orientation during play
  • Your display objects move from right to left only, never left to right

(If you need to break these rules, there are solutions available, they're just more complicated than the simple version I'll show here)

To start, create a copy of your central camera, call it "wraparound"

  • Make it a child of the central camera (for ease of positioning)
  • Remove its AudioListener (so all audio is heard by just one camera, and we don't get errors)
  • Set its Depth to 0 (instead of the default -1, so it renders after the central cam)
  • Set is Clear Flags to "Don't Clear" (so it keeps the colour & depth drawn by the central cam)

Attach to it a script something like this:

public class WraparoundCamera : MonoBehaviour {
    // Quick & dirty singleton.
    public static WraparoundCamera current;

    Camera central;
    float halfViewWidth;

    void Awake() {
        // Make ourselves easy for other scripts to find.
        WraparoundCamera.current = this;

        // Position this camera to butt up to the central camera's left edge.
        central = transform.parent.GetComponent<Camera>();
        halfViewWidth = central.aspect * central.orthographicSize;
        transform.localPosition = Vector3.left * halfViewWidth * 2f;
    }

    // Objects will call this to wrap themselves around to the other side of the view.
    public bool WrapMeIfNeeded(Renderer renderer) {
        // If the object is still in range to be seen by the central camera, don't move it.
        if(renderer.bounds.max.x >= -halfViewWidth)
            return false;

        // Once it's passed the left edge of the central camera,
        // teleport it over on full view width, so it's at the right edge.
        renderer.transform.position += Vector3.right * halfViewWidth * 2f;
        return true;
    }
}

Then your moving objects can use a script a bit like this:

void Update() {
    transform.position += velocity * Time.deltaTime;
    WraparoundCamera.current.WrapMeIfNeeded(renderer);
}
\$\endgroup\$
5
  • \$\begingroup\$ but I would do this with a shader :) \$\endgroup\$ Commented Aug 22, 2019 at 2:05
  • \$\begingroup\$ @SeyedMortezaKamali good luck using a shader when you want to use unity's new HDRP pipelines and stuff and still use all their new features. \$\endgroup\$
    – WDUK
    Commented Aug 23, 2020 at 2:59
  • \$\begingroup\$ Both camera stacking and custom shader effects can be done with Unity's new scriptable render pipelines - you just have to attack the problem a little differently. \$\endgroup\$
    – DMGregory
    Commented Aug 23, 2020 at 3:01
  • \$\begingroup\$ @WDUK you can easily convert my shader to shader graph if you need a shader graph version I can make it in my free time \$\endgroup\$ Commented Aug 23, 2020 at 5:26
  • \$\begingroup\$ Well shaders are way beyond my skill level, but if you do make it - definitely post it on git hub i think many would find it useful ! \$\endgroup\$
    – WDUK
    Commented Aug 23, 2020 at 5:36

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .