Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 35|回复: 0

unity3d shader编程中GrabPass 在某些android手机上失效的解决方案

[复制链接]
  • TA的每日心情
    奋斗
    昨天 21:54
  • 签到天数: 95 天

    [LV.6]常住居民II

    1378

    主题

    1435

    帖子

    5万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    50644
    发表于 2021-6-14 12:28:02 | 显示全部楼层 |阅读模式

    有个著名的扭曲效果的SHADER如下所示

     

    // Upgrade NOTE: replaced 'glstate.matrix.modelview[0]' with 'UNITY_MATRIX_MV'
    // Upgrade NOTE: replaced 'glstate.matrix.mvp' with 'UNITY_MATRIX_MVP'

    Shader "HeatDistortion" {
    Properties {
    _NoiseTex ("Noise Texture (RG)", 2D) = "white" {}
    strength("strength", Range(0.1, 0.3)) = 0.2
    transparency("transparency", Range(0.01, 0.1)) = 0.05
    }

    Category {
    Tags { "Queue" = "Transparent+10" }
    SubShader {
    GrabPass {
    Name "BASE"
    Tags { "LightMode" = "Always" }
    }

    Pass {
    Name "BASE"
    Tags { "LightMode" = "Always" }
    Fog { Color (0,0,0,0) }
    Lighting Off
    Cull Off
    ZWrite On
    ZTest LEqual
    Blend SrcAlpha OneMinusSrcAlpha
    AlphaTest Greater 0


    CGPROGRAM
    // Upgrade NOTE: excluded shader from DX11 and Xbox360; has structs without semantics (struct v2f members distortion)
    #pragma exclude_renderers d3d11 xbox360
    // Upgrade NOTE: excluded shader from Xbox360; has structs without semantics (struct v2f members distortion)
    #pragma exclude_renderers xbox360
    #pragma vertex vert
    #pragma fragment frag
    #pragma fragmentoption ARB_precision_hint_fastest
    #pragma fragmentoption ARB_fog_exp2
    #include "UnityCG.cginc"

    sampler2D _GrabTexture : register(s0);
    float4 _NoiseTex_ST;
    sampler2D _NoiseTex;
    float strength;
    float transparency;

    struct data {
    float4 vertex : POSITION;
    float3 normal : NORMAL;
    float4 texcoord : TEXCOORD0;
    };

    struct v2f {
    float4 position : POSITION;
    float4 screenPos : TEXCOORD0;
    float2 uvmain : TEXCOORD2;
    float distortion;
    };

    v2f vert(data i){
    v2f o;
    o.position = mul(UNITY_MATRIX_MVP, i.vertex); // compute transformed vertex position
    o.uvmain = TRANSFORM_TEX(i.texcoord, _NoiseTex); // compute the texcoords of the noise
    //float viewAngle = dot(normalize(mul((float3x3)glstate.matrix.invtrans.modelview[0], i.normal)),
    // float3(0,0,1));
    float viewAngle = dot(normalize(ObjSpaceViewDir(i.vertex)),
    i.normal);
    o.distortion = viewAngle * viewAngle; // square viewAngle to make the effect fall off stronger
    float depth = -mul( UNITY_MATRIX_MV, i.vertex ).z; // compute vertex depth
    o.distortion /= 1+depth; // scale effect with vertex depth
    o.distortion *= strength; // multiply with user controlled strength
    o.screenPos = o.position; // pass the position to the pixel shader
    return o;
    }

    half4 frag( v2f i ) : COLOR
    {
    // compute the texture coordinates
    float2 screenPos = i.screenPos.xy / i.screenPos.w; // screenpos ranges from -1 to 1
    screenPos.x = (screenPos.x + 1) * 0.5; // I need 0 to 1
    screenPos.y = (screenPos.y + 1) * 0.5; // I need 0 to 1

    if (_ProjectionParams.x < 0)
    screenPos.y = 1 - screenPos.y;

    // get two offset values by looking up the noise texture shifted in different directions
    half4 offsetColor1 = tex2D(_NoiseTex, i.uvmain + _Time.xz);
    half4 offsetColor2 = tex2D(_NoiseTex, i.uvmain - _Time.yx);

    // use the r values from the noise texture lookups and combine them for x offset
    // use the g values from the noise texture lookups and combine them for y offset
    // use minus one to shift the texture back to the center
    // scale with distortion amount
    screenPos.x += ((offsetColor1.r + offsetColor2.r) - 1) * i.distortion;
    screenPos.y += ((offsetColor1.g + offsetColor2.g) - 1) * i.distortion;

    half4 col = tex2D( _GrabTexture, screenPos );
    col.a = i.distortion/transparency;
    return col;
    }

    ENDCG
    }
    }
    }

    }

     

    这个SHADER是一个很好的SHADER,它可以用来做火焰的扭曲模仿效果也可以用来做地震波的效果。

    做地震波的效果的方法是先做一个环形的MESH,然后将这个SHADER给MESH材质使用,然后

    通过脚本改变MESH的半径从而实现地震波使地形扭曲的效果。

     

    在IOS上当然是没有问题了,可是在某些android机上发现这个效果竟然实现不了,跟踪程序发现,原来是

    在这些Aandroid机上SHADER里的GrabPass方法失效了。这可如何是好呢?

     

    经过分析发现GrabPass无非就是采集了当前的texture而已,所以试着用CAMERA的render texture功能,结果轻松的

    实现了GrabPass的功能。

    首先将上面的SHADER改为如下:(具体改的地方请自己比对)

    // Upgrade NOTE: replaced 'glstate.matrix.modelview[0]' with 'UNITY_MATRIX_MV'
    // Upgrade NOTE: replaced 'glstate.matrix.mvp' with 'UNITY_MATRIX_MVP'

    Shader "HeatDistortionNew" {
    Properties {
    _MainTex ("Main Texture (RG)", 2D) = "white" {}
    _NoiseTex ("Noise Texture (RG)", 2D) = "white" {}
    strength("strength", Range(0.01, 0.1)) = 0.04
    transparency("transparency", Range(0.01, 0.1)) = 0.01
    }

    Category {
    //Tags { "Queue" = "Transparent+10" }
    Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Opaque"}
    SubShader {
    // GrabPass {
    // Name "BASE"
    // Tags { "LightMode" = "Always" }
    //}

    Pass {
    Name "BASE"
    Tags { "LightMode" = "Always" }
    Fog { Color (0,0,0,0) }
    Lighting Off
    Cull Off
    ZWrite On
    ZTest LEqual
    Blend SrcAlpha OneMinusSrcAlpha
    AlphaTest Greater 0


    CGPROGRAM
    // Upgrade NOTE: excluded shader from DX11 and Xbox360; has structs without semantics (struct v2f members distortion)
    #pragma exclude_renderers d3d11 xbox360
    // Upgrade NOTE: excluded shader from Xbox360; has structs without semantics (struct v2f members distortion)
    #pragma exclude_renderers xbox360
    #pragma vertex vert
    #pragma fragment frag
    #pragma fragmentoption ARB_precision_hint_fastest
    #pragma fragmentoption ARB_fog_exp2
    #include "UnityCG.cginc"

    sampler2D _MainTex : register(s0);
    float4 _NoiseTex_ST;
    sampler2D _NoiseTex;
    float strength;
    float transparency;
    uniform float _BumpAmt;
    float4 _MainTex_TexelSize;

    struct data {
    float4 vertex : POSITION;
    float3 normal : NORMAL;
    float4 texcoord : TEXCOORD0;
    };

    struct v2f {
    float4 position : POSITION;
    float4 screenPos : TEXCOORD0;
    float2 uvmain : TEXCOORD2;
    float distortion;
    };

    v2f vert(data i){
    v2f o;
    o.position = mul(UNITY_MATRIX_MVP, i.vertex); // compute transformed vertex position
    o.uvmain = TRANSFORM_TEX(i.texcoord, _NoiseTex); // compute the texcoords of the noise
    //float viewAngle = dot(normalize(mul((float3x3)glstate.matrix.invtrans.modelview[0], i.normal)),
    // float3(0,0,1));
    float viewAngle = dot(normalize(ObjSpaceViewDir(i.vertex)),
    i.normal);
    o.distortion = viewAngle * viewAngle; // square viewAngle to make the effect fall off stronger
    float depth = -mul( UNITY_MATRIX_MV, i.vertex ).z; // compute vertex depth
    o.distortion /= 1+depth; // scale effect with vertex depth
    o.distortion *= strength; // multiply with user controlled strength
    o.screenPos = o.position; // pass the position to the pixel shader
    return o;
    }

    half4 frag( v2f i ) : COLOR
    {
    // compute the texture coordinates
    float2 screenPos = i.screenPos.xy / i.screenPos.w; // screenpos ranges from -1 to 1
    screenPos.x = (screenPos.x + 1) * 0.5; // I need 0 to 1
    screenPos.y = (screenPos.y + 1) * 0.5; // I need 0 to 1

    if (_ProjectionParams.x < 0)
    screenPos.y = 1 - screenPos.y;

    // get two offset values by looking up the noise texture shifted in different directions
    half4 offsetColor1 = tex2D(_NoiseTex, i.uvmain + _Time.xz);
    half4 offsetColor2 = tex2D(_NoiseTex, i.uvmain - _Time.yx);

    // use the r values from the noise texture lookups and combine them for x offset
    // use the g values from the noise texture lookups and combine them for y offset
    // use minus one to shift the texture back to the center
    // scale with distortion amount
    screenPos.x += ((offsetColor1.r + offsetColor2.r) - 1) * i.distortion;
    screenPos.y += ((offsetColor1.g + offsetColor2.g) - 1) * i.distortion;

    half4 col = tex2D( _MainTex, screenPos );
    col.a = i.distortion/transparency;
    return col;
    }

     

    ENDCG
    }
    }
    }

    }

     

    然后再写一个脚本如下:

    using UnityEngine;
    using System.Collections;

    public class Heat : MonoBehaviour {

    public Camera c;
    Material m;
    public RenderTexture t;
    // Use this for initialization
    void Start () {
    m = GetComponent<MeshRenderer>().material;
    Instantiate(c, Camera.mainCamera.transform.position, Camera.mainCamera.transform.rotation);
    }

    // Update is called once per frame
    void Update () {
    m.SetTexture("_MainTex", t);
    }

    }

    注意的地方是:CAMERA当然是你的相机了,RenderTexture t 是你要绑上去的。

    这个问题就得到了解决。。。。。

     

     

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2021-8-3 09:02 , Processed in 0.061118 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2020, Tencent Cloud.

    快速回复 返回顶部 返回列表