2013-09-03 09:51:27 woailvmengmeng 阅读数 9287



一.创建一个cube将CubeCM代码赋给它。


  1. using UnityEngine;
  2. using System.Collections;
  3. public class CubeCM : MonoBehaviour {
  4. void OnMouseDown(){
  5. if(Input.GetMouseButtonDown(0)){
  6. CMater.i++;
  7. }
  8. }
  9. }
复制代码

二.创建CMater脚本拖给桌布。


  1. using UnityEngine;
  2. using System.Collections;
  3. public class CMater : MonoBehaviour {
  4. public Texture t1;
  5. public Texture t2;
  6. public Texture t3;
  7. static public int i=0;
  8. void Update(){
  9. if(i%3==0){
  10. renderer.material.mainTexture=t1;
  11. }
  12. if(i%3==1){
  13. renderer.material.mainTexture=t2;
  14. }
  15. if(i%3==2){
  16. renderer.material.mainTexture=t3;
  17. }
  18. }
  19. }
复制代码


* 版权声明:转载时请以超链接形式标明文章原始出处和作者信息

* 本文来自:Unity3D 教程手册

* 本文链接:http://www.unitymanual.com/3210.html

2013-01-26 23:13:02 yuyingwin 阅读数 665

材质更换:
              通过点击物体选取,并通过按钮给物体赋予不同的贴图

截屏:通过按钮截取屏幕,并实现本地存储,适用于PC机单机作品

下载路径:http://115.com/u/84345888    文件名 更换物体材质及截屏存储(本地)

2013-10-14 19:49:57 u011838628 阅读数 9032

      最近在看Unity3D的人物模型和动画。所以今天先说下人物的换装吧。相信大家都玩过网游吧,没有玩过的也相信见过,就是网游或者单机游戏里的人物会有更换服装,更换武器的功能。如果外形(mesh)是一样的,那么把贴图换下就好,但是如果外形不一样甚至骨骼都变了的话,就需要我们今天讨论的技术了。

  一.Unity3D里的3D模型

Unity3D里的基础模型是从3D工具中导出来的fbx文件。把fbx放在Assets目录下会自动生成一个Materials文件夹,里面会生成一个材质球。在Unity3D项目里的显示是这样

注意:Textrue需要另外添加进去。

         模型的主要文件就是那个蓝色的方块,前面两个(WGKS_wugang,WGKS_yaodai)这两个文件是模型的Mesh信息,一个是人物本身的,一个是腰带的,因为比较简单的模型,所以只有两个。下面的一坨是动作信息,动作是可以自己设置的,这个以后文章会讲。而紧接着的

“Bip001”这个是模型的骨骼信息,你拖到Scene里就能层层打开看到了。而WGKS_yaodai则是蒙皮信息的一些玩意。选择到它会在Inspector属性栏里看到SkinnedMeshRenderer组件,这里会看到它牵扯到的mesh,material,bone信息。

  

  二.换装方案1组合模型的显示和隐藏

  这个题目可能说的不合适,但是想不到更合适的了。我们的第一种换装的方法很简单,就是让模型或者Mesh进行显示和隐藏。就比如让人物穿两套衣服,显示第一套的时候隐藏第二套,显示第二套的时候显示第一套。

         例如这个模型:

         

这里有TBJ_SR_01和TBJ_SR_03两个SkinnedMeshRenderer.那么我们可以分别设置Active来设置是否可见。代码如下:

public GameObject clothA = null;
public GameObject clothB = null;

if (GUI.Button(new Rect(5, 5, 100, 50), "ClothA"))
{
    clothA.SetActive(true);
    clothB.SetActive(false);
}

if (GUI.Button(new Rect(5, 60, 100, 50), "ClothB"))
{
    clothA.SetActive(false);
    clothB.SetActive(true);
}


运行起来的效果如下:

ClothA

ClothB

      如果角色是换武器而不是换装备的话,原理是一样的,只不过我们要找到附属的武器GameObject然后设置让它显示和隐藏就可以了。

  三.换装方案2 替换Skin信息

      方案1的方法用起来比较简单,比较适合简单的模型替换,比如一个模型来来回回就两把武器的话,就可以用。但是如果一个模型有十来套衣服或者十几件装备的话,这么做会比较悲剧的,因为太占资源了,创建一个模型,牵扯的不用的东西也整进内存了,暴殄天物。

      所以我想能不能游戏运行的时候替换模型的Skin信息达到我们的目的。一开始我觉得,其实我们只需要把sharedmesh,material替换掉就行了。实验证明不行的。大家可以自己尝试下,Unity3D会报错,即使不报错模型也会变形的。模型中还有一块是骨骼没有动,所以我想尝试下如果把骨骼去掉能不能拿到mesh信息等,然后再替换。结果是从3DMAX里去掉骨骼导出的话,蒙皮信息也没有了。所以我确定了一点是,被换装的模型必须有骨架,而源Mesh信息中必须包含骨架信息,按照我的理解就是Mesh中保存着这个点依附的是哪个骨头,权重是多少等。

 

  这里我准备了两个模型:

            

带有完整的信息(骨头,动作,蒙皮信息等,只不过模型只有一个mesh而已)。

放在Scene的样子:

            

  我的目的是想让左边的那个模型读取右边模型的SkinnedMeshRenderer信息,然后赋值给自己。首先我把右边的模型除了骨架的所以资源赋值给一个prefab,然后加载prefab,读取信息给左边的模型。

  代码如下:

// 声明两个SkinnedMeshRenderer
public SkinnedMeshRenderer MyskinMeshRender = null;
public SkinnedMeshRenderer SrcSkinMeshRender = null;

//加载资源
Object Src = Resources.Load("Res/Materials2");
objSrc = Instantiate(Src) as GameObject;

//找到目标模型的SkinnedMeshRenderer
MyskinMeshRender = GameObject.Find("TBJ_SR_01").GetComponent<SkinnedMeshRenderer>();
//获取加载的SkinnedMeshRenderer
SrcSkinMeshRender = objSrc.GetComponent<SkinnedMeshRenderer>();
//获取目标模型的骨骼
Transform[] bonesMy = gameObject.GetComponentsInChildren<Transform>();
Debug.Log(bonesMy.Length);
//Transform[] bonesSrc = GameObject.Find("TBJ_SR_03").GetComponentsInChildren<Transform>();
//获得源SkinMesh中依附的骨骼信息
Transform[] bonesSrc = SrcSkinMeshRender.bones;
Debug.Log(bonesSrc.Length);

//根据源SkinMesh依附的骨骼信息重新排列目标骨骼
List<Transform> bones = new List<Transform>();
foreach (Transform boneS in bonesSrc)
{
    foreach (Transform boneM in bonesMy)
    {
        if (boneS != null && boneM != null)
        {
            if (boneS.name != boneM.name)
            {
                continue;
            }
            bones.Add(boneM);
        }
    }
}
MyskinMeshRender.bones = bones.ToArray();
MyskinMeshRender.sharedMesh = SrcSkinMeshRender.sharedMesh;
MyskinMeshRender.sharedMaterials =SrcSkinMeshRender.sharedMaterials;     


运行之后发现皮肤换了,而且动画信息没有丢失掉,也就是说还能动,但是有个奇葩的现象,人物是倒着的,如图:

  这个我分析后觉得是因为骨骼的问题。两个模型的骨骼有点不一样。因为我是读取了右边的模型的蒙皮信息对应的骨骼信息而重组了左边的骨骼,但是左边的动画信息还是按照原来的。虽然不是很清楚动画数据里面数据结构,但是我觉得就是记录的骨骼或者mesh或者当前模型的世界坐标的某个点对应的Mesh或者骨骼移动到哪个位置。

 

  接着我换了一个思路,用一个人物模型,一套骨骼,一套动作,不过蒙皮信息有两个,导出fbx。

如图:

 

  然后在3DMax里面导出一个没有蒙皮信息只有骨骼和动作的fbx,如图:

  然后添加脚本,代码如下: 

//声明两个SkinMeshRender 声明为public是为了方便观察 真正需要private
public SkinnedMeshRenderer MyskinMeshRender = null;
public SkinnedMeshRenderer SrcSkinMeshRender = null;

//添加SkinnedMeshRenderer组件
MyskinMeshRender = gameObject.AddComponent<SkinnedMeshRenderer>();
	
if (Input.GetKeyDown(KeyCode.Z))
{
    GameObject obj = GameObject.Find("TBJ_SR_01") as GameObject;
    SrcSkinMeshRender = GameObject.Find("TBJ_SR_01").GetComponent<SkinnedMeshRenderer>();

    Transform[] bonesMy = gameObject.GetComponentsInChildren<Transform>();
    Transform[] bonesSrc = SrcSkinMeshRender.bones;

    List<Transform> bones = new List<Transform>();
    foreach (Transform boneM in bonesSrc)
    {
        foreach (Transform boneS in bonesMy)
        {
            if (boneM != null && boneS != null)
            {
                if (boneM.name != boneS.name)
                {
                    continue;
                }
                bones.Add(boneS);
            }
        }
    }
    MyskinMeshRender.bones = bones.ToArray();
    MyskinMeshRender.sharedMesh = SrcSkinMeshRender.sharedMesh;
    MyskinMeshRender.sharedMaterials = SrcSkinMeshRender.sharedMaterials;
}


 

  运行,结果没有问题了。如图:

  

  按下Z之后:

  而且动作保留。

 

  总结:

  虽然这个例子不是很经典,也存在些许问题,希望大家指出问题,共同进步。在添加skinnedMeshRenderer组件的时候有个问题,如果模型选择Generic的时候,Unity3D会挂掉。

这个例子可以运用到骨骼和动作基本一样,但是外形不同的模型中,减少游戏中的资源重复占用。网上还有个更经典的例子,运用的是Character Customization 包,运用的原理是一样的,这里给大家看下运行结果:

  

      

  这个模型是由各个部分的mesh组成,而我的例子是用的一个mesh。在复杂的模型中,我们可以查找子组件的SkinnedMeshRenderer,然后进行操作就可以了。想换哪里就替换哪里的SkinnedMeshRenderer的信息,更新对应的骨骼列表和组合一下网格就行了。

List<CombineInstance> combineInstances = new List<CombineInstance>();
CombineInstance ci = new CombineInstance();
ci.mesh = SrcSkinMeshRender.sharedMesh;
combineInstances.Add(ci);


         还有一个想法是这样的,源资源中是否需要骨头。我发现重组骨头结构的时候其实只是读取了骨头的列表信息,所以我觉得可以写成一个配置信息,直接读取配置信息来重组。这个想法还没有得到验证,等有时间的吧。

 

 

2014-10-21 14:49:21 alayeshi 阅读数 2868
直接将以下代码附加在要换贴图的模型上即可。

var textures : Texture2D[]; //声明一个数组型的图片库;  
private var i : float = 0; //声明i为浮点数0;  
function Update ()   
 
   if ("这里写上发生这个事件的条件")   
    
      i++ //切换图片  
    
   renderer.material.mainTexture = textures[i];   
}  
 

 版权声明:转载时请以超链接形式标明文章原始出处和作者信息

 本文来自:Unity3D 教程手册

2016-12-31 01:11:20 u012741077 阅读数 3872

本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);
                });
            }
        }
        //
    }
}

这里写图片描述

没有更多推荐了,返回首页