欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Unity3D Shader实现贴图切换效果

程序员文章站 2022-10-15 14:29:50
本文实例为大家分享了shader实现基于世界坐标的贴图置换效果。 效果如下: 设置面板如下: 可在面板上设置切换方向,与切换对象,及其切换速度。 shade...

本文实例为大家分享了shader实现基于世界坐标的贴图置换效果。

效果如下:

Unity3D Shader实现贴图切换效果

设置面板如下:

Unity3D Shader实现贴图切换效果

可在面板上设置切换方向,与切换对象,及其切换速度。

shader实现如下:

shader "xm/effect/swaptexture" {
 properties {
 _color ("color", color) = (1,1,1,1)
 _maintex ("albedo (rgb)", 2d) = "white" {}
 _targettex ("target tex", 2d) = "white" {}//目标贴图
 [keywordenum(up, down, left, right, forward, back)] _mode ("mode", int) = 0//切换方向
 _swapblend ("blend", range(0,1)) = 0//0-1混合值
 _swapmin("min value", float) = 0//最小世界坐标
 _swapmax("max value", float) = 0//最大世界坐标
 _glossiness ("smoothness", range(0,1)) = 0.5
 _metallic ("metallic", range(0,1)) = 0.0
 }
 subshader {
 tags { "rendertype"="opaque" }
 lod 200

 cgprogram
 // physically based standard lighting model, and enable shadows on all light types
 #pragma surface surf standard fullforwardshadows vertex:vert

 // use shader model 3.0 target, to get nicer looking lighting
 #pragma target 3.0

 sampler2d _maintex;
 sampler2d _targettex;

 struct input {
  float2 uv_maintex;
  float3 worldpos;
 };

 half _mode;
 half _swapblend;
 float _swapmin;
 float _swapmax;
 half _glossiness;
 half _metallic;
 fixed4 _color;

 void vert (inout appdata_full v, out input o) {
  unity_initialize_output(input,o);
 }

 void surf (input in, inout surfaceoutputstandard o) {
  half usetarget = 0;
  float targetvalue = 0;
  switch(_mode)//模式选择
  {
  case 0://up
   targetvalue = (_swapmax - _swapmin) * _swapblend + _swapmin;
   usetarget = in.worldpos.y > targetvalue?0:1;
   break;
  case 1://down
   targetvalue = (_swapmax - _swapmin) * (1 - _swapblend) + _swapmin;
   usetarget = in.worldpos.y < targetvalue?0:1;
   break;
  case 2://left
   targetvalue = (_swapmax - _swapmin) * (1 - _swapblend) + _swapmin;
   usetarget = in.worldpos.x < targetvalue?0:1;
   break;
  case 3://right
   targetvalue = (_swapmax - _swapmin) * _swapblend + _swapmin;
   usetarget = in.worldpos.x > targetvalue?0:1;
   break;
  case 4://forward
   targetvalue = (_swapmax - _swapmin) * _swapblend + _swapmin;
   usetarget = in.worldpos.z > targetvalue?0:1;
   break;
  case 5://back
   targetvalue = (_swapmax - _swapmin) * (1 - _swapblend) + _swapmin;
   usetarget = in.worldpos.z < targetvalue?0:1;
   break;
  }

  // albedo comes from a texture tinted by color
  fixed4 c;
  if(usetarget == 1)
  {
  c = tex2d (_targettex, in.uv_maintex);
  }
  else
  {
  c = tex2d (_maintex, in.uv_maintex);
  }


  c *= _color;
  o.albedo = c.rgb;
  // metallic and smoothness come from slider variables
  o.metallic = _metallic;
  o.smoothness = _glossiness;
  o.alpha = c.a;
 }
 endcg
 }
 fallback "diffuse"
}

配合使用的脚本如下:

using system;
using system.collections;
using unityengine;

namespace xm.effect
{
 public class swaptexture : monobehaviour
 {
  public enum swapdirection
  {
   up,
   down,
   left,
   right,
   forward,
   back
  }

  public shader _shader;//"xm/effect/swaptexture” shader
  public swapdirection _swapdir;//切换方向
  public renderer _target;//目标对象
  [range(0, 1)]
  public float _speed;//速度

  private material _matold;
  private material _matnew;

  public void swap(texture tex, action<bool> oncomplete)
  {
   if (_matold != null)
   {
    stopallcoroutines();
    if (null != oncomplete)
    {
     oncomplete(false);
    }

    _target.material = _matold;
   }

   _matold = _target.material;

   _matnew = new material(_shader);
   _matnew.settexture("_maintex", _target.material.gettexture("_maintex"));
   _matnew.settexture("_targettex", tex);
   _matnew.setint("_mode", (int)_swapdir);
   _matnew.setfloat("_swapblend", 0);

   startcoroutine("_startchange", oncomplete);
  }

  private ienumerator _startchange(action<bool> oncomplete)
  {
   float deltaval = 0;

   _target.material = _matnew;

   vector3 vtmin;
   vector3 vtmax;
   float minval = 0;
   float maxval = 0;

   while (deltaval != 1)
   {
    vtmin = _target.bounds.min;
    vtmax = _target.bounds.max;

    switch (_swapdir)
    {
     case swapdirection.up:
     case swapdirection.down:
      minval = vtmin.y;
      maxval = vtmax.y;
      break;
     case swapdirection.left:
     case swapdirection.right:
      minval = vtmin.x;
      maxval = vtmax.x;
      break;
     case swapdirection.forward:
     case swapdirection.back:
      minval = vtmin.z;
      maxval = vtmax.z;
      break;
    }

    minval -= 0.01f;
    maxval += 0.01f;

    _matnew.setfloat("_swapmin", minval);
    _matnew.setfloat("_swapmax", maxval);

    deltaval = mathf.clamp01(deltaval + _speed * time.deltatime);
    _matnew.setfloat("_swapblend", deltaval);
    yield return null;
   }

   _matold.settexture("_maintex", _matnew.gettexture("_targettex"));
   _target.material = _matold;

   _matnew = null;
   _matold = null;

   if (null != oncomplete)
   {
    oncomplete(true);
   }
  }

  public void ondrawgizmos()
  {
   if (_target != null)
   {
    gizmos.drawwirecube(_target.bounds.center, _target.bounds.size);
    gizmos.drawwiresphere(_target.bounds.min, 0.1f);
    gizmos.drawwiresphere(_target.bounds.max, 0.1f);
   }
  }

  //test
  public texture testtex;
  private void ongui()
  {
   if (guilayout.button("swaptexture"))
   {
    swap(testtex, (t) =>
    {
     debug.log("swap>" + t);
    });
   }
  }
  //
 }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。