0

I'm currently playing a movie in Unity using MovieTexture and applying a custom shader to allow an alpha channel. Problem is I need to have the top half of the video masked and nothing seems to work. I believe it's the shader preventing it (correct me if I'm wrong).

I tried 3 different masking techniques:

  • Standard Mask component on the video layer (quad) with a black and transparent PNG image as mask.
  • DepthMask applied to a 3D object intersecting video layer - Uses a special shader that affects render queue or draw calls (I forget) to prevent anything from being drawn that is behind or within the 3D object.
  • Putting the quad inside a Canvas and Panel UI layer and adjusting them so canvas and panel are half the size of the video layer. (Had to use a quad as I don't believe you can add a materiel to a UI element?)

None of these are blocking any of the video, unfortunately.

(This is the alpha shader I'm using: https://github.com/keijiro/AotsMovieTexture)

Here's the code for the shader as well:

Shader "Custom/Aots Movie Texture" {
    Properties
    {
        _MainTex("Base Texture", 2D) = "" {}
        _ColorTint("Color Tint", Color) = (0.5, 0.5, 0.5, 1)
    }

    CGINCLUDE

#include "UnityCG.cginc"

sampler2D _MainTex;
half4 _ColorTint;

struct v2f
{
    float4 position : SV_POSITION;
    float2 texcoord : TEXCOORD0;
};

v2f vert(appdata_base v)
{
    v2f o;
    o.position = mul(UNITY_MATRIX_MVP, v.vertex);
    o.texcoord = v.texcoord;
    return o;
}

float4 frag(v2f i) : SV_Target 
{
    float2 uv1 = i.texcoord;
    float2 uv2 = i.texcoord;

    uv1.x *= 0.5f;
    uv2.x *= 0.5f;
    uv2.x += 0.5f;

    half4 color = tex2D(_MainTex, uv1);
    half4 mask = tex2D(_MainTex, uv2);

    color.rgb *= _ColorTint.rgb * 2;
    color.a = mask.r * _ColorTint.a;

    return color;
}

    ENDCG

    SubShader
    {
        Tags { "RenderType"="Transparent" "Queue"="Transparent" }
        Pass
        {
            ZTest Always Cull Off ZWrite Off
            Fog { Mode off }
            Blend SrcAlpha OneMinusSrcAlpha
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            ENDCG
        }
    } 
}

Edit:

Just explain in more details what I'm looking to do, we have a 4K video divided into quads. Top two quads will be independent videos and bottom two will be used for the alpha videos. I just need the top two quads (top half of the 4k video) hidden, so you only see the alpha channel when the video is layered on top like the shader I linked to. enter image description here

KeepCool
  • 497
  • 1
  • 6
  • 24
  • Hi, you should not be using MoveTexture at this time, Check [this](https://stackoverflow.com/questions/41144054/using-new-unity-videoplayer-and-videoclip-api-to-play-video) post for new way to play video in Unity. – Programmer Jul 25 '17 at 02:15
  • Hi! I can rewrite this shader and just cut the top part of the video, but maybe you wanna something more, idk. Plz describe the issue in detail and add screenshots how it must be. – nipercop Jul 25 '17 at 05:15
  • That would be amazing. I would love to get into shaders, but it looks very complicated. I'll edit the main post to add what we're looking to accomplish. – KeepCool Jul 25 '17 at 17:06
  • I'd love to know which part of the shader lets you manipulate what part of the video is show as well, since we might have to change it in the future a little. – KeepCool Jul 25 '17 at 17:29
  • Programmer: Thanks for the heads up. I'm still using 5.4 until 2017 was officially released, but I just noticed it's now released. – KeepCool Jul 25 '17 at 17:31

1 Answers1

1

So, shader will be look like that:

Shader "StackOverFlow/splitVideo"{
    Properties
    {
        _MainTex("Base Texture", 2D) = "" {}
        _ColorTint("Color Tint", Color) = (0.5, 0.5, 0.5, 1)
        [MaterialToggle]ShowLeft("Show Only Left", Float) = 0 
        [MaterialToggle]ShowRight("Show Only Right", Float) = 0
    }

    CGINCLUDE

    #include "UnityCG.cginc"
    #pragma multi_compile _ SHOWLEFT_ON
    #pragma multi_compile _ SHOWRIGHT_ON
    sampler2D _MainTex;
    half4 _ColorTint;

    struct v2f
    {
        float4 position : SV_POSITION;
        float2 texcoord : TEXCOORD0;
    };

    v2f vert(appdata_base v)
    {
        v2f o;
        o.position = UnityObjectToClipPos(v.vertex);
        o.texcoord = v.texcoord;
        return o;
    }

    float4 frag(v2f i) : SV_Target
    {
        float2 uv1 = i.texcoord;
        float2 uv2 = i.texcoord;

#ifdef SHOWLEFT_ON   
        uv1.x *= 0.5;
        uv2.x *= 0.5;
#else
#ifdef SHOWRIGHT_ON
        uv1.x *= 0.5;
        uv2.x *= 0.5;
        uv2.x += 0.5;
        uv1.x += 0.5;
#endif  
#endif          
        uv1.y *= 0.5; // line 1
        uv1.y += 0.5; // line 2
        uv2.y *= 0.5;

        half4 color = tex2D(_MainTex, uv1);
        half4 mask = tex2D(_MainTex, uv2);

        color.rgb *= _ColorTint.rgb * 2;
        color.a = mask.b *_ColorTint.a;

        return color;
    }

    ENDCG

    SubShader
    {
        Tags{ "RenderType" = "Transparent" "Queue" = "Transparent" }
        Pass
        {
            ZTest Always Cull Off ZWrite Off
            Fog{ Mode off }
            Blend SrcAlpha OneMinusSrcAlpha
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            ENDCG
        }
    }
}

About vertex and fragment shaders you can read here.

Let's explain, what is going on here! (in offsets)

We want to see our videos cutted by alpha masks! (isn't it?)

I using that texture (or video. it doesn't matter):

image and coordinates

By default your Fragment will looks like that:

 float4 frag(v2f i) : SV_Target
 {
     half4 color = tex2D(_MainTex, i.texcoord);
     return color;
 }

First step, let's try to draw both videos on quad without masks!

To do that, let's save default texture coordinates in temp variable float2 uv1 = i.texcoord;. And multiply uv1.y by 0.5; what we will see, and why we do that?

mouse & kitty masks

We seem to have stretched the texture twice vertically, and shader draws only bottom half of the texture. Because uv.y coords of top half outside of quad. Yes it is good, but we want videos! So, let's move the texture vertically by half size of texture coords uv1.y +=0.5. What we have?

video 1 & 2

Yes! Our videos is best! (example to draw only videos)

 float4 frag(v2f i) : SV_Target
 {
     float2 uv1 = i.texcoord;
     uv1.y *= 0.5;
     uv1.y += 0.5;
     half4 color = tex2D(_MainTex, uv1);
     return color;
 }

Second step. To use masks, we need two variables to use it! Our texture is single, but we have to use it like it's two different. (videos and masks)! Declare a new variable

float2 uv2 = i.texcoord;

and cut top half videos uv2.y *= 0.5;. Same story as uv1, but without move the texture. Second variable will be

half4 mask = tex2D(_MainTex, uv2);

Animals is our friends! We do not see them, but they see us!

Since we use black color to cut, we can assign the alpha channel of videos from the current color of masks.

color.a = mask.r;

mouse kitty final

simple Shader without any settings will look like this:

float4 frag(v2f i) : SV_Target
{
    float2 uv1 = i.texcoord;
    float2 uv2 = i.texcoord;      
    uv1.y *= 0.5;
    uv1.y += 0.5;
    uv2.y *= 0.5;
    half4 color = tex2D(_MainTex, uv1);
    half4 mask = tex2D(_MainTex, uv2);
    color.a = mask.r;
    return color;
}

To control alpha and current color of videos let's add _ColorTint:

//...
half4 mask = tex2D(_MainTex, uv2);
color.rgb *= _ColorTint.rgb * 2;
color.a = mask.r *_ColorTint.a;
return color;
//...

So, you can ask me, -"why you are using mask.r?", -"r is RED?", -"why not g or b?"

Answer: black color is (0,0,0) and white is (1,1,1). If i use other channels(g or b), it will not change anything. When you multiply "color.a" to 0, it will be Tranparent.

That's all.

Sorry for my bad and poor English!

nipercop
  • 357
  • 1
  • 11
  • This kind of works. I feel like with the nice info you gave me I could probably figure it out. It doesn't show the top quads, but right now it used the Alpha quad (bottom right) to mask the the bottom left and top right quad. Really strange. And it appears squished from the sides. – KeepCool Jul 26 '17 at 17:07
  • Actually using your "Show only left/right" code seems to fix it. The squished part was easily fixed by changing the scale of the quad (silly me). But the colors are all inverted and weird. Not sure what's causing it yet. Will try a few things and report back if I find out how to fix. – KeepCool Jul 26 '17 at 17:17
  • @KeepCool notice me if you solve the problem or not.) – nipercop Jul 27 '17 at 03:49
  • Hey nipercop. Everything works except for colors. I tried playing with all the uv numbers for x & y but I have no idea what any of them mean. The only one that seems to do anything is "uv1.y += 0.5f". If I change that to 0.0f it shows reds. But no blues. – KeepCool Jul 27 '17 at 05:54
  • @KeepCool, In `float2 uv1 = i.texcoord;` i saving texture coordinates to temp value (by default from 0 to 1), `uv1.y *= 0.5;` that mean i wanna draw bottom half of texture/video (texture will render on quad only from 0 to 0.5 by coordinates), and, `uv1.y +=0.5;` it is mean we setting offset to draw top half (will render on quad from 0.5 to 1). will tell you more aftel work =\ – nipercop Jul 27 '17 at 06:27
  • @KeepCool not so much) Ok i write you later, and, i will edit my answer in details) – nipercop Jul 27 '17 at 07:52
  • That is an amazing explanation of what is happening in the shader. Thanks so much!! I feel bad, though, cause it's not exactly what we need it to do. I'm going to update my post with an image of exactly what we need. We need it to do exactly what the original shader did, but mask the top half of the video, since we don't use it at all for this. – KeepCool Jul 27 '17 at 20:52
  • I got it working! I used your explanation of how the shader works and played with the uv2.y values and it works! I would love for you to email me (if you want) nipercop. I really really appreciate all the work and explanation you gave. – KeepCool Jul 27 '17 at 21:05