zoukankan      html  css  js  c++  java
  • VPOS VS_POSITION ComputeScreenPos 使用场景

    VPOS 
    VPOS 是比较新的概念,在Unity2018中可以使用(估计Unity5开始的特性?),而在我的旧项目中(使用Unity4.6.4) 上会报错,所以我后来使用了SV_POSITION.xy
    但是经过测试 在Unity2018Build Android之后 放在低性能的安卓主板上(3188) 下方的Shader会显示全透明,显然是因为显卡不支持吧。

    Shader "Unlit/Screen Position"
    {
        Properties
        {
            _MainTex("Texture", 2D) = "white" {}
        }
        SubShader
        {
            Pass
            {
                Cull Off
                Lighting Off
                ZWrite Off
                Fog { Mode Off }
                Offset -1, -1
                Blend SrcAlpha OneMinusSrcAlpha
                
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                #pragma target 3.0
    
                // note: no SV_POSITION in this struct
                struct v2f {
                    float2 uv : TEXCOORD0;
                };
    
                v2f vert(
                    float4 vertex : POSITION, // vertex position input
                    float2 uv : TEXCOORD0, // texture coordinate input
                    out float4 outpos : SV_POSITION // clip space position output
                    )
                {
                    v2f o;
                    o.uv = uv;
                    //outpos = UnityObjectToClipPos(vertex);
                    outpos = UnityObjectToClipPos(vertex);
                    return o;
                }
    
                sampler2D _MainTex;
    
                fixed4 frag(v2f i, UNITY_VPOS_TYPE screenPos : VPOS) : SV_Target
                {
                    // screenPos.xy 将包含像素的整数坐标值。
                    // 用它们实现棋盘团来,替代渲染4x4的像素块(4x4纹理)
    
                    // 棋盘图案每个格将使用4x4的像素块
                    //screenPos.xy = floor(screenPos.xy * 0.25) * 0.5;
                    
                    screenPos.xy = floor(screenPos.xy) * 0.5;
                    float checker = -frac(screenPos.r + screenPos.g);
    
                    // 如果checker为负数,则使用HLSL 内置函数 clip 来停止绘制该像素
                    clip(checker);
    
                    // 保持绘制的像素将采样纹理值并输出
                    fixed4 c = tex2D(_MainTex, i.uv);
                    return c;
                }
                ENDCG
            }
        }
    }


    VS_POSITION 
    VS_POSITION 和 POSITION的区别 大家可以自行查找,我用 VS_POSITION 重写了上面的Shader后,在PC可以使用,但是在3188 和 3399上都无法使用(原图输出,没有输出棋盘状)。
    其原因是 在PC上, 依然会将各顶点(o.pos)进行插值后的交给 fragment。但是在Android上 获取到 的  pos值是(0,0,0,0) ,也就是说vert之后就已经跳过了pos的处理。

    Shader "Custom/ScreenPos" {
        Properties
        {
            _MainTex ("Texture", 2D) = "white" {}
        }
        SubShader
        {
        Tags
            {
                "Queue" = "Transparent"
                "IgnoreProjector" = "True"
                "RenderType" = "Transparent"
            }
            
            Pass
            {
                Cull Off
                Lighting Off
                ZWrite Off
                Fog { Mode Off }
                Offset -1, -1
                Blend SrcAlpha OneMinusSrcAlpha
    
                CGPROGRAM
                #include "UnityCG.cginc"
                
                #pragma vertex vert
                #pragma fragment frag
                
                struct appdata_t
                {
                    float4 vertex : POSITION;
                    float2 uv : TEXCOORD0;
                };
        
                struct v2f
                {
                    float4 pos : SV_POSITION;
                    half2 uv : TEXCOORD0;
                };
    
                v2f vert (appdata_t v)
                {
                    v2f o;
                    o.uv = v.uv;
                    o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
                    
                    return o;
                }
    
                sampler2D _MainTex;
    
                fixed4 frag (v2f i) : SV_Target
                {
                    // checker value will be negative for 4x4 blocks of pixels
                    // in a checkerboard pattern
                    float2 screenPos = i.pos.xy;
                    screenPos.xy = floor(screenPos.xy) *0.5;// 0.25;
                    float checker = -frac(screenPos.x + screenPos.y); 
    
                    // clip HLSL instruction stops rendering a pixel if value is negative
                    //clip(checker);
                    
                    if(checker < 0)
                        return fixed4(0,0,0,0);
    
                    // for pixels that were kept, read the texture and output it
                    fixed4 c = tex2D (_MainTex, i.uv);
                    return c;
                    
                }
                ENDCG
            }
        }
    }

    ComputeScreenPos
    因为VS_POSITION在3188不起作用的原因,我辗转使用了很多不同的着色器语义(NORMAL, TEXCOORD_X,...)等用来保存 pos变量,但是均已失败告终,后来发现UnityCG.cginc 内部包含了 ComputeScreenPos函数,便尝试了一下,发现真的可行!其在vert阶段使用了TEXCOORD_X保存转换后的坐标,再在frag阶段讲变量还原。而我失败的原因是没有经过转换!至于为什么要转换,我估计是转换成采样uv的等同坐标,这样在vert 到 frag的时候数据才不会走样。还有ComputeScreenPos这个函数的分析,网上都有。

    Shader "Custom/ScreenPos" {
        Properties
        {
            _MainTex ("Texture", 2D) = "white" {}
        }
        SubShader
        {
        Tags
            {
                "Queue" = "Transparent"
                "IgnoreProjector" = "True"
                "RenderType" = "Transparent"
            }
            
            Pass
            {
                Cull Off
                Lighting Off
                ZWrite Off
                Fog { Mode Off }
                Offset -1, -1
                Blend SrcAlpha OneMinusSrcAlpha
    
                CGPROGRAM
                #include "UnityCG.cginc"
                
                #pragma vertex vert
                #pragma fragment frag
                
                struct appdata_t
                {
                    float4 vertex : POSITION;
                    float2 uv : TEXCOORD0;
                };
        
                struct v2f
                {
                    float4 pos : SV_POSITION;
                    half2 uv : TEXCOORD0;
                    float4 screenPos : TEXCOORD1;
                };
    
                v2f vert (appdata_t v)
                {
                    v2f o;
                    o.uv = v.uv;
                    o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
                    o.screenPos = ComputeScreenPos(o.pos);
                    //o.screenPos.xy /= o.screenPos.w;
                    
                    return o;
                }
    
                sampler2D _MainTex;
    
                fixed4 frag (v2f i) : SV_Target
                {
                    // checker value will be negative for 4x4 blocks of pixels
                    // in a checkerboard pattern
                 float2 screenPos = i.screenPos.xy;// / i.screenPos.w;
                  screenPos.xy *= _ScreenParams.xy;
                  screenPos.xy = floor(screenPos.xy) *0.5;// 0.25;
                    float checker = -frac(screenPos.x + screenPos.y); 
    
                    // clip HLSL instruction stops rendering a pixel if value is negative
                    //clip(checker);
                    
                    if(checker < -0.25)
                        return fixed4(0,0,0,0);
    
                    // for pixels that were kept, read the texture and output it
                    fixed4 c = tex2D (_MainTex, i.uv);
                    return c;
                    
                }
                ENDCG
            }
        }
    }

    简单说就是 ComputeScreenPos 是可以兼容低端显卡的做法(我用的3188),使用ComputeScreenPos在PC上效果还可以,但是在3188上效果不好,等于没用。但是总算是找出了解决方案。

    参考:
    https://blog.csdn.net/lt136022740/article/details/52859545
    https://www.cnblogs.com/tekkaman/p/9606319.html
    https://blog.csdn.net/linuxheik/article/details/86691117


    unity3d, shader中  把一个定点惊醒mpv变换后,得到的一个float4的这个值,其实还并没有进行透视除法,需要我们手动的去除以最后一个w分量,这也是在计算屏幕坐标(ComputeScreenPos这个函数,定义在unitycg.cginc中)的时候,我最开始理解的一个误区)
    ————————————————
    版权声明:本文为CSDN博主「lt136022740」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/lt136022740/java/article/details/52859545


    现在一目了然了,ComputeScreenPos返回的值是齐次坐标系下的屏幕坐标值,其范围为[0, w]。那么为什么Unity要这么做呢?Unity的本意是希望你把该坐标值用作tex2Dproj指令的参数值,tex2Dproj会在对纹理采样前除以w分量。当然你也可以像下面代码那样自己除以w分量后进行采样,但是效率不如内置指令tex2Dproj:

    1. pos = UnityObjectToClipPos(v.vertex);
    2. screenPos = ComputeScreenPos(o.pos);
    3. tex2D(_ScreenTex, float2(screenPos.xy / screenPos.w))
  • 相关阅读:
    Scrapy框架实现持久化存储
    Scrapy框架的介绍和基本使用
    处理页面动态加载数据
    爬虫数据解析
    Python爬虫基础
    Flask详解(下篇)
    Flask详解(中篇)
    CentOS 中的性能监测命令vmstat
    CentOS 7安装MySQL 8.0.15
    CF B.Kind Anton(4月8号)
  • 原文地址:https://www.cnblogs.com/godzza/p/12910903.html
Copyright © 2011-2022 走看看