Unity - 2d Shader ,edge highlight on objects ,colliders or 2d textures

Hi Guys and Girls. I need your guidance on this. Platforms are not visible but similar to GOnner and the player reveals the edges of the world around him. So what I am looking to do is the following. The 2 object is the platforms that you interact with. But they are not visible. Only the red sections on the platform etc will show to the player when he is close to them.
image

Please help me brainstorm this.

I was thinking of raycasting to the objects around to reveal but this will be performance heavy? Hit Shader then Revealing it but 2d?

The video below does a similar thing but with animation that looks great.


Comments

  • edited
    At the most basic level you'd want to create an image effect/screen shader that discards any pixels not within range of the player. That would be my starting approach.

    Here is a quick and (very) janky version of it.

    image

    Here's the shader code
    Shader "Hidden/WorldCutout"
    {
    	Properties
    	{
    		_MainTex ("Texture", 2D) = "white" {}
    		_Range("Reveal Range", float) = 2
    		_RevealPoint("Point to reveal from", Vector) = (0, 0, 0, 0)
    	}
    	SubShader
    	{
    		// No culling or depth
    		Cull Off ZWrite Off ZTest Always
    
    		Pass
    		{
    			CGPROGRAM
    			#pragma vertex vert
    			#pragma fragment frag
    			
    			#include "UnityCG.cginc"
    
    			struct appdata
    			{
    				float4 vertex : POSITION;
    				float2 uv : TEXCOORD0;
    			};
    
    			struct v2f
    			{
    				float2 uv : TEXCOORD0;
    				float4 vertex : SV_POSITION;
    			};
    
    			v2f vert (appdata v)
    			{
    				v2f o;
    				o.vertex = UnityObjectToClipPos(v.vertex);
    				o.uv = v.uv;
    				return o;
    			}
    			
    			sampler2D _MainTex;
    			float _Range;
    			float4 _RevealPoint;
    
    			fixed4 frag (v2f i) : SV_Target
    			{
    				fixed4 col = tex2D(_MainTex, i.uv);
    
    				float distanceFromPoint = distance(i.vertex, _RevealPoint);
    
    
    				//The following can be used to get a nice fade instead of hard edges.
    				//float rangeFromPoint = saturate((_Range/distanceFromPoint));
    				//rangeFromPoint = 1 - pow(rangeFromPoint,8);
    				//col = lerp(col, 0, rangeFromPoint);
    
    				col = step(distanceFromPoint, _Range) * col;
    
    				return col;
    			}
    			ENDCG
    		}
    	}
    }


    and the script to set the screen effect...

    [ExecuteInEditMode]
    public class WorldCutoutScreenShader : MonoBehaviour 
    {
    	public float range;
    	public Material material;
    	public Transform revealObject;
    
    	private Camera myCamera;
    	// Creates a private material used to the effect
    	void Awake ()
    	{
    		material = new Material( Shader.Find("Hidden/WorldCutout") );
    		myCamera = GetComponent<Camera>();
    	}
    
    	// Postprocess the image
    	void OnRenderImage (RenderTexture source, RenderTexture destination)
    	{
    		material.SetVector("_RevealPoint", myCamera.WorldToScreenPoint(revealObject.position));
    		material.SetFloat("_Range", range);
    
    		Graphics.Blit (source, destination, material);
    	}
    }


    Now naturally this looks pretty bad! You can add fade to the effect which is a mild improvement or you can animate it! But that only really changes the "Reveal Circle". If you want nicely animating platforms like in GoNNER you'll need a more sophisticated solution which will probably be far off from this.

    Also keep in mind that this simple solution will discard everything not in the range. Not too nice having most of your game screen black. You can use a number of ways to avoid that, the easiest being multiple cameras and rendering "always visible" things to a separate camera.
    Mightylice.gif
    1003 x 687 - 192K
    Thanked by 1dark_seth
  • (This should be obvious, but note that you've got to fix those dumb html things in Shader pasted code that has # in them when you use them in your project, because the BBcode plugin doesn't seem to treat those consistently.)

    I'd probably look at some edge detection algorithm, and feed it your level geometry. It's no longer included in Unity by default, but you can find it on the asset store and it supposedly still works. That + bloom + sorting your cameras could look quite nice!
    Thanked by 1dark_seth
  • (This should be obvious, but note that you've got to fix those dumb html things in Shader pasted code that has # in them when you use them in your project, because the BBcode plugin doesn't seem to treat those consistently.)

    I'd probably look at some edge detection algorithm, and feed it your level geometry. It's no longer included in Unity by default, but you can find it on the asset store and it supposedly still works. That + bloom + sorting your cameras could look quite nice!
    Thanks. I looked at the edge detection but that is not for 2D. But will look into something similar. I had an idea of having sprites around the object that will animate and display when they enter the players trigger area. A round trigger around the player. Then moves back and hides when leaving the players trigger trigger. The bad thing of this is that it is a crazy ammount of manual texture placements...
  • This is what it looks like. Just used a basic block to get the Idea ( I only did the top facing side of the platform, No sides etc..). To many manual placements around the whole platform for this to work.
    What I do like is the half a second delay before it goes away.
    https://deon-smit.itch.io/effect-test

    Going to see if I cant find a shader that can show edges on 2d Sprites and somehow using what
    @Gnoblar_agency showed.
  • edited
    The itch.io link you pasted doesn't work, not exactly sure what you want to achieve, but from that example video you posted, why not just test a distance to a few vertices of the mesh that you want to make visible, if the distance is less than the threshold, enable the object?
  • dark_seth said:
    I looked at the edge detection but that is not for 2D.
    I believe edge detection algorithms just look at changes in colour, and whether it falls within some threshold that is enough to be called an edge. So an edge detection that looks at depth or normal direction to do edge detection should work just as well by feeding it any 2D image that has enough contrast to trigger the threshold.
    Thanked by 1dark_seth
  • edited
    I made a script for him using the vertices check approach. It's below for anyone interested and produces this.

    image

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class dark_seth : MonoBehaviour {
    
        public Transform ObjectsParent;
        public Transform PlayerObject;
        public float TargetDistance = 2.0f;
    
        private MeshFilter[] objects;
        private const int HowManyToCheck = 2;
        private float[] cooldowns;
    
    	// Use this for initialization
    	void Start ()
        {
            this.objects = ObjectsParent.GetComponentsInChildren<MeshFilter>();
            this.cooldowns = new float[this.objects.Length];
    	}
    	
    	// Update is called once per frame
    	void Update ()
        {
            Vector3 pos = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, 0));
            pos.z = 0;
            this.PlayerObject.position = pos;
            
            for (int i = 0; i < this.objects.Length; i++)
            {
                this.cooldowns[i] -= Time.deltaTime;
                if (this.cooldowns[i] > 0)
                    continue;
    
                bool hit = false;
                for (int c = 0; c < HowManyToCheck; c++)
                {
                    Vector3 vertice = this.objects[i].mesh.vertices[Random.Range(0, this.objects[i].mesh.vertices.Length)];
                    vertice += this.objects[i].gameObject.transform.position;
                    if (Vector3.Distance(this.PlayerObject.position, vertice) < this.TargetDistance)
                    {    
                           hit = true;
                           break;
                    }
                }
                this.objects[i].gameObject.SetActive(hit);
    
                if (hit)
                    this.cooldowns[i] = 1.0f;
            }
    	}
    }



  • So. Using all your ideas and some of my own. This is what I got for now. I do a realtime fracture of a 2d Sprite. The cool thing about this is fracture lines is always random.
    Then When player is close to each fragment it gets activated. When het gets out of range the fragment get disabled after 1 second. This is a start, not exactly what I want but a start.


    image
    Fracture2.gif
    1427 x 634 - 2M
  • That looks super cool! :D
    Thanked by 1dark_seth
  • Ooo, really nice tech. Love seeing how this progressed from an idea to actual implementation.
    Thanked by 1dark_seth
  • @dark_seth ah that's super dope!

    Knowing Ditto personally, I doubt he actually used a shader :P. He's quite the punk programmer - he probably doing individual objects with animations. So that's impressive that you got it working in one!

  • @dark_seth that looks rad!

    Do you feel like writing a bit more about the "real-time fracture of a 2d Sprite" stuff? \:D/
    Thanked by 1dark_seth
  • @dark_seth that looks rad!

    Do you feel like writing a bit more about the "real-time fracture of a 2d Sprite" stuff? \:D/
    Will do. But for now I am trying to get a type of 2d field of view working with it. Think I can get a cool looking effect going.
    Thanked by 1blacksheepZA
  • IMO just with what you have shown, you have yourself a nice little solid base for a game. Really nice, post updates as you progress, please.
    Thanked by 1dark_seth
  • Hi Guys.

    So I played around with this till early hours.. So what I got now is.... (Some prototype thing with no textures )
    A field of View that revealed objects to 20 Alpha of its color. It also activates the RED blocks ,an area reveal objects that permanently reveals objects but not yet the backdrop. This Field of view gives a mask to the shader of the backdrop hiding the rest.
    The area around the player is still based on what I showed in the previous gif.

    Like you know a made a post Rage Quit which was a hard clone of other game. Now like @critic said I feel that I have a base for some sort of game. What game.... I DON'T KNOW yet..... Ideas is welcome.


  • Great to see how all the elements came together. Looks cool!
  • Just a quick update. Field of View is adjustable. Range and Angle acting like a torch effect.

  • Looks cool as a technical demo :) The way you have a couple of different "systems of seeing" feels weird, I know it's a demo, but it would be good to tweak it so that the different systems of seeing harmonised more.
  • edited
    Tuism said:
    Looks cool as a technical demo :) The way you have a couple of different "systems of seeing" feels weird, I know it's a demo, but it would be good to tweak it so that the different systems of seeing harmonised more.
    Thanks. The problem is I got almost no idea for a game on these. So funny.... but yes, playing around with this a Idea will pop up.

    Maybe the player has 2 forms. Ghost and human. Ghost has aura reveal around it. Player has a flash light.

Sign In or Register to comment.