unity3d 没有精灵切割

2017-08-07 14:12:28 ecidevilin 阅读数 4951

Unity3D中,纹理占据着很重要的位置,包括模型的贴图,UI的精灵等都需要使用纹理。而如何导入纹理,该怎样设置,变成了一个很重要的问题。

前一篇Unity3D白皮书(一)模型导入设置介绍了Unity3D中的模型导入设置,本文继续介绍U3D中纹理的导入设置。

(注:U3D版本5.6.1f1)


如图所示,U3D中纹理的类型分为以上8种(Advanced这种类型已经被淹没在历史的尘埃里了)。

Default:默认最常用的纹理类型,大部分导入参数都可以访问。

Normal map:法线贴图。

Editor GUI and Legacy GUI:编辑器GUI和传统GUI。

Sprite(2D and UI):精灵,用于2D对象和UGUI贴图。

Cursor:自定义光标。

Cookie:场景光的Cookie。

Lightmap:光照贴图,将贴图编码成特定的格式,并对纹理数据进行后处理。

SingleChannel:单通道。


我们首先看默认类型的设置:


Texture Shape:纹理形状,2D或立方体。(详情参考TextureImporter的Texture Shape部分)
sRGB(Color Texture):指定纹理是否保存在Gamma空间。
Alpha Source: α通道来源。
  1. None:强制无α通道。
  2. Input Texture Alpha:使用纹理自带的α通道。
  3. From Gray Scale:使用纹理RGB通道的均值来生成α通道。
Alpha Is Transparency:α通道是透明度。

Non Power of 2:NPOT的处理方式。
Read/Write Enabled:读写开关,非必要不开启,否则会增加一倍的内存。
Generate Mip Maps:生成Mip Maps,会增加33%的内存。一般用于模型纹理,UI、天空盒等纹理不需要开启。
Border Mip Maps:防止低阶的Mip Map的色彩值溢出边界,一般用于光照Cookie。
Mip Map Filtering:过滤算法,Box和Kaiser
Fadeout Mip Maps:根据层阶使Mip Map慢慢变灰,一般用于细节贴图(DetailMaps)。
Wrap Mode:循环(平铺)模式,当UV<0或>1时,如何采样。
  1. Repeat:重复。
  2. Clamp:固定。
Filter Mode:滤波模式,当被3D变换拉伸时,纹理如何插值。
  1. Point(nofilter):点(无过滤),马赛克。
  2. Bilinear:双线性,模糊。
  3. Trilinear:三线性,在Bilinear的基础上对不同的Mip层阶进行模糊(插值)。

AnisoLevel:各项异性滤波(Anisotropic Filtering )等级,增加纹理在大倾角视角的质量,对底板和地表纹理效果很好。


Normal Map类型的纹理设置:


与Default相比增加了一下设置:

Create from Grayscale:从灰度高度图(Heightmap)创建。
Bumpiness:崎岖度。
Filtering:滤波算法。
  1. Smooth:平滑,标准前向差分算法。
  2. Sharp:尖锐,Sobel滤波器。
Sprite类型的纹理设置:



与Default相比增加了一下设置:

Sprite Mode:精灵模式。
  1. Single:单图。
  2. Multiple:多图。
  3. Polygon:多边形,在SpriteEditor里使用多边形裁剪精灵。

PackingTag:指定图集。

PixelsPer Unit:每单位像素数,在世界场景中,每单位距离有多少个像素。

Mesh Type:网格类型(Polygon模式无此属性)。
  1. FullRect:矩形。
  2. Tight:紧凑的,根据Alpha通道生成Mesh。(2DObject)

ExtrudeEdge:拉伸边缘。

Pivot:轴心(仅Single),精灵内部坐标的原点。


Cookie类型的纹理设置:



与Default相比增加了一下设置:

Light Type:光照类型。
  1. Spotlight:聚光灯,形状必须为2D。
  2. Directional:平行光,形状必须为2D。
  3. Point:点光源,形状必须为立方体。

最后,在这些纹理设置之下,还有针对不同平台的压缩设置:


Max Size:最大尺寸。
Compression:压缩质量。
Format:压缩格式。
Use Crunch Compression:紧凑压缩。
­Compressor Quality:压缩质量。
2016-11-29 23:46:54 Irwin2020 阅读数 498
学习了一段时间的unity,对里面的组件有一个大致的了解,但是具体操作来说还不是很熟悉,今天看了一片关于unity sprite怎么获取切割后的图的文章,感觉还不错。
  假设有一张图集,导入到Unity,放置目录"Assets/Resources/Sprites
为了可以使用Unity自带的精灵切割,要将纹理类型改成"Sprite","Sprite Mode"改成"Multiple","Format"改成"Truecolor",点击"Apply"按钮进行应用。如下图

接着,点击"Sprite Editor"打开精灵编辑器,点击左上角的"Slice"按钮,弹出切片设置,再次点击里面的"Slice"按钮,就会自动对图片进行切割,
在对切割不完整的地方进行修正后,点击右上角的"Apply"按钮,进行保存。可以看到Project视图下这个图集
接下来,因为要对图片进行读写操作,要更改图片的属性才能进行,否则会提示如下:
UnityException: Texture 'testUI' is not readable, the texture memory can not be accessed from scripts. You can make the texture readable in the Texture Import Settings.
将图片纹理类型更改为"Advanced",将"Read/Write Enabled"属性进行打勾,
创建一个脚本文件,代码如下:
using UnityEngine;
using UnityEditor;
public class TestSaveSprite
{
(MenuItem("Tools/导出精灵"))
static void SaveSprite()
{
string resourcesPath = "Assets/Resources/";
foreach (Object obj in Selection.objects)
{
string selectionPath = AssetDatabase.GetAssetPath(obj);
// 必须最上级是"Assets/Resources/"
if (selectionPath.StartsWith(resourcesPath))
{
string selectionExt = System.IO.Path.GetExtension(selectionPath);
if (selectionExt.Length == 0)
{
continue;
}
// 从路径"Assets/Resources/UI/testUI.png"得到路径"UI/testUI"
string loadPath = selectionPath.Remove(selectionPath.Length - selectionExt.Length);
loadPath = loadPath.Substring(resourcesPath.Length);
// 加载此文件下的所有资源
Sprite()sprites = Resources.LoadAll<Sprite>(loadPath);
if (sprites.Length > 0)
{
// 创建导出文件夹
string outPath = Application.dataPath + "/outSprite/" + loadPath;
System.IO.Directory.CreateDirectory(outPath);
foreach (Sprite sprite in sprites)
{
// 创建单独的纹理
Texture2D tex = new Texture2D((int)sprite.rect.width, (int)sprite.rect.height, sprite.texture.format, false);
tex.SetPixels(sprite.texture.GetPixels((int)sprite.rect.xMin, (int)sprite.rect.yMin,
(int)sprite.rect.width, (int)sprite.rect.height));
tex.Apply();
// 写入成PNG文件
System.IO.File.WriteAllBytes(outPath + "/" + sprite.name + ".png", tex.EncodeToPNG());
}
Debug.Log("SaveSprite to " + outPath);
}
}
}
Debug.Log("SaveSprite Finished");
}
}
在Unity编辑器将会看到Tools菜单下多了"导出精灵"项,选中图集,然后点击"导出精灵"菜单项,即可导出子图成功。
2017-10-16 21:09:42 qq_37712328 阅读数 9680

要求:把下面这张图片切割成一个个相应规则的图片:


一:  第一种方法(是失败的):

1,把这张图片放在桌面上,2,打开Unity, 把桌面上的图片拖曳到Assets文件夹下,如图:


3,点击Sprite Editor后,先选择Apply;紧接着出来Sprite Editor选框:在Sprite Editor中选择左上角“”Slice",紧接着出来一个小框:(1)Type:Automatic   (2) Pivot:Center  (3) Method: delete Existing    设置好这(3)项后,点击Method下面的Slice按钮。然后点击Sprite Editor右上角的Apply。关闭Sprite Editor选框。回到Assets文件夹,发现该图片并没有被切割成相应的规则的一个个小图片。【该方法失败,失败原因是:不能把图片从桌面上拖曳到Assets文件夹下,这样切不出来,只有把该图片从该图片在该电脑上的原始的位置,找到它最初的位置再把它拖曳至Assets文件夹下就可以切割出来,也就是第二种方法。】

二:第二种方法(是成功的):

1,找到该图片在该电脑上的初始位置,截图如下:


2,把该图片从它的原始位置拖曳到Unity的Assets文件夹下,截图如下:




3,打开Sprite Editor,操作和上面一样。

4,效果:成功,截图如下:




第二种方法是正确的。总结:第一种方法失败的原因是:【从桌面上拖曳到Unity】这样不行,【得从该图片在该电脑上的原始位置拖曳到Unity】这样才可以。


注意一点:




2016-01-08 11:20:51 andyhebear 阅读数 20537

Unity中经常使用到精灵,尤其是2D游戏中制作动画等!今天我们就学习下精灵的切割和导出吧!

废话不多说,先建议空的工程。

1,打开Unity建工程,同时导入素材进行资源分类,工程不在于大小,这是我们对待它的态度!

 

2.开始分割精灵,三步走!

 

编辑精灵.


开始分割精灵

Apply一下,看下分割的精灵,0-9共9个。

贴精灵导出代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
using UnityEngine;
using UnityEditor;
public class SpriteTailed:MonoBehaviour
{
[MenuItem("Tools/导出精灵")]
static void SaveSprite()
{
string resourcesPath = "Assets/Resources/";
foreach (Object obj in Selection.objects)
{
string selectionPath = AssetDatabase.GetAssetPath(obj);
 
// 必须最上级是"Assets/Resources/"
if (selectionPath.StartsWith(resourcesPath))
{
string selectionExt = System.IO.Path.GetExtension(selectionPath);
if (selectionExt.Length == 0)
{
continue;
}
 
// 从路径"Assets/Resources/Sprite/number.png"得到路径"Sprite/number"
string loadPath = selectionPath.Remove(selectionPath.Length - selectionExt.Length);
loadPath = loadPath.Substring(resourcesPath.Length);
 
// 加载此文件下的所有资源
Sprite[] sprites = Resources.LoadAll<Sprite>(loadPath);
if (sprites.Length > 0)
{
Debug.Log(sprites.Length);
// 创建导出文件夹
string outPath = Application.dataPath + "/outSprite/" + loadPath;
System.IO.Directory.CreateDirectory(outPath);
 
foreach (Sprite sprite in sprites)
{
Debug.Log("Export Sprite:" + sprite.name);
// 创建单独的纹理
Texture2D tex = new Texture2D((int)sprite.rect.width, (int)sprite.rect.height, sprite.texture.format, false);
tex.SetPixels(sprite.texture.GetPixels((int)sprite.rect.xMin, (int)sprite.rect.yMin,
(int)sprite.rect.width, (int)sprite.rect.height));
tex.Apply();
 
// 写入成PNG文件
System.IO.File.WriteAllBytes(outPath + "/" + sprite.name + ".png", tex.EncodeToPNG());
}
Debug.Log("SaveSprite to " + outPath);
}
}
}
Debug.Log("SaveSprite Finished");
}
}

将脚本挂到MainCamera上,点击Tools/导出精灵:

OK,大功告成,好了,本篇unity3d教程关于Sprite精灵的切割和导出到此结束,下篇我们再会!

2014-10-28 21:03:21 baijiajie2012 阅读数 5367

在Cocos2dx中,对大图的处理已经封装好了一套自己的API,但是在Unity3D中貌似没有类似的API(好吧,实际上是有的,而且功能更强大),或者说我没找到。不过这也在情理之中,毕竟Unity3D是做3D的,要切割图片的地方还是很少的。

因为我用Unity3D主要是用于做2D游戏的(PS:很蛋疼吧?我也觉得),所以就不得不考虑切图和播放序列帧这两个在2D上常见的功能了,下面废话不多说。我的任务是把下面这张图切割成16块,并且按照动画的序列播放出来。

目标图片

查Unity3D的使用手册的过程中,我发现了一个类:Texture2D,他是继承Texture的,主要是用于创建2D纹理的,非常符合切图的需要。

首先,我们需要加载大图,加载大图有一个非常简单的方法,就是创建一个public的Texture2D类成员变量,然后在编辑器中直接拖动到上去给他赋值就可以了。

当然也可以采用动态加载图片资源的方法,这种方法比较麻烦,需要把图片先转换成二进制流,然后赋值给Texture2D

	//加载图片资源
	void LoadTexture()
	{
		using (FileStream file = File.Open (Application.dataPath + "/Textures/Player.png", FileMode.Open))
		{
			using (BinaryReader reader = new BinaryReader(file))
			{
				m_texPlayer = new Texture2D (192, 256, TextureFormat.ARGB4444, false);
				texture.LoadImage (reader.ReadBytes((int)file.Length));
			}
		}
	}

加载完之后就要切割了,主要思路就是,两个for循环,一个表示行,一个表示列,然后再循环每个像素点,把每个像素点里面的颜色复制出来给切割的Texture2D,最后把Texture2D组合成一个4x4的矩阵数组。

下面是第一步:

        for (int i = 0; i < m_iMinPicColumnCount; ++i)
        {
            for (int j = 0; j < m_iMinPicRowCount; ++j)
                DePackTexture(i, j);
        }

上面的最终处理调用了一个DePackTexture,这个函数是用于实际上的切割的。

    //切图
    void DePackTexture(int i, int j)
    {
        int cur_x = i * m_iMinPicWidth;
        int cur_y = j * m_iMinPicHeight;

        Texture2D newTexture = new Texture2D(m_iMinPicWidth, m_iMinPicHeight);

        for (int m = cur_y; m < cur_y + m_iMinPicHeight; ++m)
        {
            for (int n = cur_x; n < cur_x + m_iMinPicWidth; ++n)
            {
                newTexture.SetPixel(n - cur_x, m - cur_y, m_texPlayer.GetPixel(n, m));
            }
        }
        newTexture.Apply();
        m_texPlayers[i, j] = newTexture;
    }
切图值得注意的就是两点,一点就是找好位置,另一点就是执行完SetPixel操作后一定要执行Apply,不然是没有效果的。

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

下面是帧序列动画,帧序列动画实际上就是将图片按照一定的顺序加载上去,值得注意的是所有的GUI操作一定要放到OnGUI里面。

    void DrawAnimation(Texture[,] tex, Rect rect)
    {
        //绘制当前帧
        GUI.DrawTexture(rect, tex[m_iCurFram, m_iCurAnimation], ScaleMode.StretchToFill, true, 0.0f);
        //计算限制帧的时间
        m_fTime += Time.deltaTime;
        //超过限制帧切换贴图
        if (m_fTime >= 1.0 / m_fFps && m_bStop == false)
        {
            //帧序列切换
            m_iCurFram = ++m_iCurFram % m_iMinPicRowCount;
            //限制帧清空
            m_fTime = 0;
            //超过帧动画总数从第0帧开始
            if (m_iCurFram >= tex.Length)
            {
                m_iCurFram = 0;
            }
        }
    }

然后没有什么了,代码还是很简单的。下面附上全部的代码,这个我做成了一个小的demo,含有动画的开始和暂停功能,而且还有动画的帧速调整的功能。(最后会附上demo的地址)

using UnityEngine;
using System.Collections;
using System;

public class CTexture : MonoBehaviour
{
    //大图的人
    public Texture2D m_texPlayer;
    //小图的人
    private Texture2D[,] m_texPlayers;
    //当前帧
    private int m_iCurFram;
    //当前动画
    private int m_iCurAnimation;
    //限制帧的时间
    private float m_fTime = 0;

    //小图的宽和高
    public int m_iMinPicWidth = 48;
    public int m_iMinPicHeight = 64;
    //一行有多少个小图
    public int m_iMinPicRowCount = 4;
    //一列有多少个小图
    public int m_iMinPicColumnCount = 4;

    //动画控制
    //暂停
    private bool m_bStop = false;
    //一秒多少帧
    private float m_fFps = 4;

    private string m_sFps = "";

    void Start()
    {
		m_texPlayers = new Texture2D[4, 4];	
		m_iCurAnimation = 0;
        m_sFps = m_fFps.ToString();
		//加载图片资源
		LoadTexture();

        for (int i = 0; i < m_iMinPicColumnCount; ++i)
        {
            for (int j = 0; j < m_iMinPicRowCount; ++j)
                DePackTexture(i, j);
        }
    }

    void Update()
    {
        if(Input.GetKeyDown(KeyCode.A))
        {
            m_iCurAnimation = 2;
        }
        if (Input.GetKeyDown(KeyCode.S))
        {
            m_iCurAnimation = 3;
        }
        if (Input.GetKeyDown(KeyCode.W))
        {
            m_iCurAnimation = 0;
        }
        if (Input.GetKeyDown(KeyCode.D))
        {
            m_iCurAnimation = 1;
        }
    }

    void OnGUI()
    {
        DrawAnimation(m_texPlayers, new Rect(100, 100, m_iMinPicWidth, m_iMinPicHeight));
        
        if(GUI.Button(new Rect(200,20,80,50),"开始/暂停"))
        {
            m_bStop = m_bStop == false ? true : false ;
        }

        m_sFps = GUI.TextField(new Rect(200, 80, 80, 40), m_sFps);
        if (GUI.Button(new Rect(200, 150, 50, 40), "应用"))
        {
            m_fFps = float.Parse(m_sFps);
        }
    }
	
	//加载图片资源
	void LoadTexture()
	{
		using (FileStream file = File.Open (Application.dataPath + "/Textures/Player.png", FileMode.Open))
		{
			using (BinaryReader reader = new BinaryReader(file))
			{
				m_texPlayer = new Texture2D (192, 256, TextureFormat.ARGB4444, false);
				texture.LoadImage (reader.ReadBytes((int)file.Length));
			}
		}
	}

    //切图
    void DePackTexture(int i, int j)
    {
        int cur_x = i * m_iMinPicWidth;
        int cur_y = j * m_iMinPicHeight;

        Texture2D newTexture = new Texture2D(m_iMinPicWidth, m_iMinPicHeight);

        for (int m = cur_y; m < cur_y + m_iMinPicHeight; ++m)
        {
            for (int n = cur_x; n < cur_x + m_iMinPicWidth; ++n)
            {
                newTexture.SetPixel(n - cur_x, m - cur_y, m_texPlayer.GetPixel(n, m));
            }
        }
        newTexture.Apply();
        m_texPlayers[i, j] = newTexture;
    }

    void DrawAnimation(Texture[,] tex, Rect rect)
    {
        //绘制当前帧
        GUI.DrawTexture(rect, tex[m_iCurFram, m_iCurAnimation], ScaleMode.StretchToFill, true, 0.0f);
        //计算限制帧的时间
        m_fTime += Time.deltaTime;
        //超过限制帧切换贴图
        if (m_fTime >= 1.0 / m_fFps && m_bStop == false)
        {
            //帧序列切换
            m_iCurFram = ++m_iCurFram % 4;
            //限制帧清空
            m_fTime = 0;
            //超过帧动画总数从第0帧开始
            if (m_iCurFram >= tex.Length)
            {
                m_iCurFram = 0;
            }
        }
    }
}

demo地址:http://download.csdn.net/detail/baijiajie2012/8092625