1. 程式人生 > >Unity3D實用指令碼(二)—— 檢查場景中用到的資源

Unity3D實用指令碼(二)—— 檢查場景中用到的資源

在專案的開發過程中,經常需要檢查場景中所用到的資源,例如Textures,Materials,Meshs等。

今天來實現如圖所示的資源檢查功能。


程式碼如下:

// Resource Checker
// (c) 2012 Simon Oliver / HandCircus / [email protected]
// Public domain, do with whatever you like, commercial or not
// This comes with no warranty, use at your own risk!
// https://github.com/handcircus/Unity-Resource-Checker

using System.Linq;
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;


public class TextureDetails
{
	public bool isCubeMap;
	public int memSizeKB;
	public Texture texture;
	public TextureFormat format;
	public int mipMapCount;
	public List<Object> FoundInMaterials=new List<Object>();
	public List<Object> FoundInRenderers=new List<Object>();
	public TextureDetails()
	{
		
	}
};

public class MaterialDetails
{
	
	public Material material;

	public List<Renderer> FoundInRenderers=new List<Renderer>();

	public MaterialDetails()
	{
		
	}
};

public class MeshDetails
{
	
	public Mesh mesh;

	public List<MeshFilter> FoundInMeshFilters=new List<MeshFilter>();
	public List<SkinnedMeshRenderer> FoundInSkinnedMeshRenderer=new List<SkinnedMeshRenderer>();

	public MeshDetails()
	{
		
	}
};

public class ResourceChecker : EditorWindow {
	
	
	string[] inspectToolbarStrings = {"Textures", "Materials","Meshes"};
	
	enum InspectType 
	{
		Textures,Materials,Meshes
	};
	
	InspectType ActiveInspectType=InspectType.Textures;
	
	float ThumbnailWidth=40;
	float ThumbnailHeight=40;
	
	List<TextureDetails> ActiveTextures=new List<TextureDetails>();
	List<MaterialDetails> ActiveMaterials=new List<MaterialDetails>();
	List<MeshDetails> ActiveMeshDetails=new List<MeshDetails>();
	
	Vector2 textureListScrollPos=new Vector2(0,0);
	Vector2 materialListScrollPos=new Vector2(0,0);
	Vector2 meshListScrollPos=new Vector2(0,0);
	
	int TotalTextureMemory=0;
	int TotalMeshVertices=0;
	
	bool ctrlPressed=false;
	
	static int MinWidth=455;
    
	[MenuItem ("Custom/Resource Checker")]
    static void Init ()
	{  
        ResourceChecker window = (ResourceChecker) EditorWindow.GetWindow (typeof (ResourceChecker));
		window.CheckResources();
		window.minSize=new Vector2(MinWidth,300);
    }
    
    void OnGUI ()
	{
		if (GUILayout.Button("Refresh")) CheckResources();
		GUILayout.BeginHorizontal();
		GUILayout.Label("Materials "+ActiveMaterials.Count);
		GUILayout.Label("Textures "+ActiveTextures.Count+" - "+FormatSizeString(TotalTextureMemory));
		GUILayout.Label("Meshes "+ActiveMeshDetails.Count+" - "+TotalMeshVertices+" verts");
		GUILayout.EndHorizontal();
		ActiveInspectType=(InspectType)GUILayout.Toolbar((int)ActiveInspectType,inspectToolbarStrings);
		
		ctrlPressed=Event.current.control || Event.current.command;
		
		switch (ActiveInspectType)
		{
			case InspectType.Textures:
				ListTextures();
				break;
			case InspectType.Materials:
				ListMaterials();
				break;
			case InspectType.Meshes:
				ListMeshes();
				break;	
			
			
		}
	}
	
	
	int GetBitsPerPixel(TextureFormat format)
	{
		switch (format)
		{
			case TextureFormat.Alpha8: //	 Alpha-only texture format.
				return 8;
			case TextureFormat.ARGB4444: //	 A 16 bits/pixel texture format. Texture stores color with an alpha channel.
				return 16;
			case TextureFormat.RGBA4444: //	 A 16 bits/pixel texture format.
				return 16;
			case TextureFormat.RGB24:	// A color texture format.
				return 24;
			case TextureFormat.RGBA32:	//Color with an alpha channel texture format.
				return 32;
			case TextureFormat.ARGB32:	//Color with an alpha channel texture format.
				return 32;
			case TextureFormat.RGB565:	//	 A 16 bit color texture format.
				return 16;
			case TextureFormat.DXT1:	// Compressed color texture format.
				return 4;
			case TextureFormat.DXT5:	// Compressed color with alpha channel texture format.
				return 8;
			/*
			case TextureFormat.WiiI4:	// Wii texture format.
			case TextureFormat.WiiI8:	// Wii texture format. Intensity 8 bit.
			case TextureFormat.WiiIA4:	// Wii texture format. Intensity + Alpha 8 bit (4 + 4).
			case TextureFormat.WiiIA8:	// Wii texture format. Intensity + Alpha 16 bit (8 + 8).
			case TextureFormat.WiiRGB565:	// Wii texture format. RGB 16 bit (565).
			case TextureFormat.WiiRGB5A3:	// Wii texture format. RGBA 16 bit (4443).
			case TextureFormat.WiiRGBA8:	// Wii texture format. RGBA 32 bit (8888).
			case TextureFormat.WiiCMPR:	//	 Compressed Wii texture format. 4 bits/texel, ~RGB8A1 (Outline alpha is not currently supported).
				return 0;  //Not supported yet
			*/
			case TextureFormat.PVRTC_RGB2://	 PowerVR (iOS) 2 bits/pixel compressed color texture format.
				return 2;
			case TextureFormat.PVRTC_RGBA2://	 PowerVR (iOS) 2 bits/pixel compressed with alpha channel texture format
				return 2;
			case TextureFormat.PVRTC_RGB4://	 PowerVR (iOS) 4 bits/pixel compressed color texture format.
				return 4;
			case TextureFormat.PVRTC_RGBA4://	 PowerVR (iOS) 4 bits/pixel compressed with alpha channel texture format
				return 4;
			case TextureFormat.ETC_RGB4://	 ETC (GLES2.0) 4 bits/pixel compressed RGB texture format.
				return 4;
			case TextureFormat.ATC_RGB4://	 ATC (ATITC) 4 bits/pixel compressed RGB texture format.
				return 4;
			case TextureFormat.ATC_RGBA8://	 ATC (ATITC) 8 bits/pixel compressed RGB texture format.
				return 8;
			case TextureFormat.BGRA32://	 Format returned by iPhone camera
				return 32;
			//case TextureFormat.ATF_RGB_DXT1://	 Flash-specific RGB DXT1 compressed color texture format.
			//case TextureFormat.ATF_RGBA_JPG://	 Flash-specific RGBA JPG-compressed color texture format.
			//case TextureFormat.ATF_RGB_JPG://	 Flash-specific RGB JPG-compressed color texture format.
			//	return 0; //Not supported yet
		}
		return 0;
	}
	
	int CalculateTextureSizeBytes(Texture tTexture)
	{
		
		int tWidth=tTexture.width;
		int tHeight=tTexture.height;
		if (tTexture is Texture2D)
		{
			Texture2D tTex2D=tTexture as Texture2D;
		 	int bitsPerPixel=GetBitsPerPixel(tTex2D.format);
			int mipMapCount=tTex2D.mipmapCount;
			int mipLevel=1;
			int tSize=0;
			while (mipLevel<=mipMapCount)
			{
				tSize+=tWidth*tHeight*bitsPerPixel/8;
				tWidth=tWidth/2;
				tHeight=tHeight/2;
				mipLevel++;
			}
			return tSize;
		}
		
		if (tTexture is Cubemap)
		{
			Cubemap tCubemap=tTexture as Cubemap;
		 	int bitsPerPixel=GetBitsPerPixel(tCubemap.format);
			return tWidth*tHeight*6*bitsPerPixel/8;
		}
		return 0;
	}
	
	
	void SelectObject(Object selectedObject,bool append)
	{
		if (append)
		{
			List<Object> currentSelection=new List<Object>(Selection.objects);
			// Allow toggle selection
			if (currentSelection.Contains(selectedObject)) currentSelection.Remove(selectedObject);
			else currentSelection.Add(selectedObject);
			
			Selection.objects=currentSelection.ToArray();
		}
		else Selection.activeObject=selectedObject;
	}
	
	void SelectObjects(List<Object> selectedObjects,bool append)
	{
		if (append)
		{
			List<Object> currentSelection=new List<Object>(Selection.objects);
			currentSelection.AddRange(selectedObjects);
			Selection.objects=currentSelection.ToArray();
		}
		else Selection.objects=selectedObjects.ToArray();
	}
	
	void ListTextures()
	{
		textureListScrollPos = EditorGUILayout.BeginScrollView(textureListScrollPos);
		
		foreach (TextureDetails tDetails in ActiveTextures)
		{			
			
			GUILayout.BeginHorizontal ();
			GUILayout.Box(tDetails.texture, GUILayout.Width(ThumbnailWidth), GUILayout.Height(ThumbnailHeight));
			
			if(GUILayout.Button(tDetails.texture.name,GUILayout.Width(150)))
			{
				SelectObject(tDetails.texture,ctrlPressed);
			}
			
			string sizeLabel=""+tDetails.texture.width+"x"+tDetails.texture.height;
			if (tDetails.isCubeMap) sizeLabel+="x6";
			sizeLabel+=" - "+tDetails.mipMapCount+"mip";
			sizeLabel+="\n"+FormatSizeString(tDetails.memSizeKB)+" - "+tDetails.format+"";
			
			GUILayout.Label (sizeLabel,GUILayout.Width(120));
					
			if(GUILayout.Button(tDetails.FoundInMaterials.Count+" Mat",GUILayout.Width(50)))
			{
				SelectObjects(tDetails.FoundInMaterials,ctrlPressed);
			}
			
			if(GUILayout.Button(tDetails.FoundInRenderers.Count+" GO",GUILayout.Width(50)))
			{
				List<Object> FoundObjects=new List<Object>();
				foreach (Renderer renderer in tDetails.FoundInRenderers) FoundObjects.Add(renderer.gameObject);
				SelectObjects(FoundObjects,ctrlPressed);
			}
			
			GUILayout.EndHorizontal();	
		}
		if (ActiveTextures.Count>0)
		{
			GUILayout.BeginHorizontal ();
			GUILayout.Box(" ",GUILayout.Width(ThumbnailWidth),GUILayout.Height(ThumbnailHeight));
			
			if(GUILayout.Button("Select All",GUILayout.Width(150)))
			{
				List<Object> AllTextures=new List<Object>();
				foreach (TextureDetails tDetails in ActiveTextures) AllTextures.Add(tDetails.texture);
				SelectObjects(AllTextures,ctrlPressed);
			}
			EditorGUILayout.EndHorizontal();
		}
		EditorGUILayout.EndScrollView();
    }
	
	void ListMaterials()
	{
		materialListScrollPos = EditorGUILayout.BeginScrollView(materialListScrollPos);
		
		foreach (MaterialDetails tDetails in ActiveMaterials)
		{			
			if (tDetails.material!=null)
			{
				GUILayout.BeginHorizontal ();
				
				if (tDetails.material.mainTexture!=null) GUILayout.Box(tDetails.material.mainTexture, GUILayout.Width(ThumbnailWidth), GUILayout.Height(ThumbnailHeight));
				else	
				{
					GUILayout.Box("n/a",GUILayout.Width(ThumbnailWidth),GUILayout.Height(ThumbnailHeight));
				}
				
				if(GUILayout.Button(tDetails.material.name,GUILayout.Width(150)))
				{
					SelectObject(tDetails.material,ctrlPressed);
				}
				
				string shaderLabel = tDetails.material.shader != null ? tDetails.material.shader.name : "no shader";
				GUILayout.Label (shaderLabel, GUILayout.Width(200));

				if(GUILayout.Button(tDetails.FoundInRenderers.Count+" GO",GUILayout.Width(50)))
				{
					List<Object> FoundObjects=new List<Object>();
					foreach (Renderer renderer in tDetails.FoundInRenderers) FoundObjects.Add(renderer.gameObject);
					SelectObjects(FoundObjects,ctrlPressed);
				}
				
				
				GUILayout.EndHorizontal();	
			}
		}
		EditorGUILayout.EndScrollView();		
    }
	
	void ListMeshes()
	{
		meshListScrollPos = EditorGUILayout.BeginScrollView(meshListScrollPos);
		
		foreach (MeshDetails tDetails in ActiveMeshDetails)
		{			
			if (tDetails.mesh!=null)
			{
				GUILayout.BeginHorizontal ();
				/*
				if (tDetails.material.mainTexture!=null) GUILayout.Box(tDetails.material.mainTexture, GUILayout.Width(ThumbnailWidth), GUILayout.Height(ThumbnailHeight));
				else	
				{
					GUILayout.Box("n/a",GUILayout.Width(ThumbnailWidth),GUILayout.Height(ThumbnailHeight));
				}
				*/
				
				if(GUILayout.Button(tDetails.mesh.name,GUILayout.Width(150)))
				{
					SelectObject(tDetails.mesh,ctrlPressed);
				}
				string sizeLabel=""+tDetails.mesh.vertexCount+" vert";
				
				GUILayout.Label (sizeLabel,GUILayout.Width(100));
				
				
				if(GUILayout.Button(tDetails.FoundInMeshFilters.Count + " GO",GUILayout.Width(50)))
				{
					List<Object> FoundObjects=new List<Object>();
					foreach (MeshFilter meshFilter in tDetails.FoundInMeshFilters) FoundObjects.Add(meshFilter.gameObject);
					SelectObjects(FoundObjects,ctrlPressed);
				}
				
				if(GUILayout.Button(tDetails.FoundInSkinnedMeshRenderer.Count + " GO",GUILayout.Width(50)))
				{
					List<Object> FoundObjects=new List<Object>();
					foreach (SkinnedMeshRenderer skinnedMeshRenderer in tDetails.FoundInSkinnedMeshRenderer) FoundObjects.Add(skinnedMeshRenderer.gameObject);
					SelectObjects(FoundObjects,ctrlPressed);
				}
				
				
				GUILayout.EndHorizontal();	
			}
		}
		EditorGUILayout.EndScrollView();		
    }
	
	string FormatSizeString(int memSizeKB)
	{
		if (memSizeKB<1024) return ""+memSizeKB+"k";
		else
		{
			float memSizeMB=((float)memSizeKB)/1024.0f;
			return memSizeMB.ToString("0.00")+"Mb";
		}
	}
	
	
	TextureDetails FindTextureDetails(Texture tTexture)
	{
		foreach (TextureDetails tTextureDetails in ActiveTextures)
		{
			if (tTextureDetails.texture==tTexture) return tTextureDetails;
		}
		return null;
		
	}
	
	MaterialDetails FindMaterialDetails(Material tMaterial)
	{
		foreach (MaterialDetails tMaterialDetails in ActiveMaterials)
		{
			if (tMaterialDetails.material==tMaterial) return tMaterialDetails;
		}
		return null;
		
	}
	
	MeshDetails FindMeshDetails(Mesh tMesh)
	{
		foreach (MeshDetails tMeshDetails in ActiveMeshDetails)
		{
			if (tMeshDetails.mesh==tMesh) return tMeshDetails;
		}
		return null;
		
	}
		
	
	void CheckResources()
	{
		ActiveTextures.Clear();
		ActiveMaterials.Clear();
		ActiveMeshDetails.Clear();
		
		Renderer[] renderers = (Renderer[]) FindObjectsOfType(typeof(Renderer));
		//Debug.Log("Total renderers "+renderers.Length);
		foreach (Renderer renderer in renderers)
		{
			//Debug.Log("Renderer is "+renderer.name);
			foreach (Material material in renderer.sharedMaterials)
			{
				
				MaterialDetails tMaterialDetails=FindMaterialDetails(material);
				if (tMaterialDetails==null)
				{
					tMaterialDetails=new MaterialDetails();
					tMaterialDetails.material=material;
					ActiveMaterials.Add(tMaterialDetails);
				}
				tMaterialDetails.FoundInRenderers.Add(renderer);
			}
		}
		
		foreach (MaterialDetails tMaterialDetails in ActiveMaterials)
		{
			Material tMaterial=tMaterialDetails.material;
			var dependencies = EditorUtility.CollectDependencies(new UnityEngine.Object[] {tMaterial});
			foreach (Object obj in dependencies)
		    {
				if (obj is Texture)
				{
					Texture tTexture=obj as Texture;
					var tTextureDetail = GetTextureDetail(tTexture, tMaterial, tMaterialDetails);
					ActiveTextures.Add(tTextureDetail);
				}
		    }

			//if the texture was downloaded, it won't be included in the editor dependencies
			if (tMaterial.mainTexture != null && !dependencies.Contains(tMaterial.mainTexture))
			{
				var tTextureDetail = GetTextureDetail(tMaterial.mainTexture, tMaterial, tMaterialDetails);
				ActiveTextures.Add(tTextureDetail);
			}
		}
		
		
		MeshFilter[] meshFilters = (MeshFilter[]) FindObjectsOfType(typeof(MeshFilter));
		
		foreach (MeshFilter tMeshFilter in meshFilters)
		{
			Mesh tMesh=tMeshFilter.sharedMesh;
			if (tMesh!=null)
			{
				MeshDetails tMeshDetails=FindMeshDetails(tMesh);
				if (tMeshDetails==null)
				{
					tMeshDetails=new MeshDetails();
					tMeshDetails.mesh=tMesh;
					ActiveMeshDetails.Add(tMeshDetails);
				}
				tMeshDetails.FoundInMeshFilters.Add(tMeshFilter);
			}
		}
		
		SkinnedMeshRenderer[] skinnedMeshRenderers = (SkinnedMeshRenderer[]) FindObjectsOfType(typeof(SkinnedMeshRenderer));
		
		foreach (SkinnedMeshRenderer tSkinnedMeshRenderer in skinnedMeshRenderers)
		{
			Mesh tMesh=tSkinnedMeshRenderer.sharedMesh;
			if (tMesh!=null)
			{
				MeshDetails tMeshDetails=FindMeshDetails(tMesh);
				if (tMeshDetails==null)
				{
					tMeshDetails=new MeshDetails();
					tMeshDetails.mesh=tMesh;
					ActiveMeshDetails.Add(tMeshDetails);
				}
				tMeshDetails.FoundInSkinnedMeshRenderer.Add(tSkinnedMeshRenderer);
			}
		}
		
	
		TotalTextureMemory=0;
		foreach (TextureDetails tTextureDetails in ActiveTextures) TotalTextureMemory+=tTextureDetails.memSizeKB;
		
		TotalMeshVertices=0;
		foreach (MeshDetails tMeshDetails in ActiveMeshDetails) TotalMeshVertices+=tMeshDetails.mesh.vertexCount;
		
		// Sort by size, descending
		ActiveTextures.Sort(delegate(TextureDetails details1, TextureDetails details2) {return details2.memSizeKB-details1.memSizeKB;});
		ActiveMeshDetails.Sort(delegate(MeshDetails details1, MeshDetails details2) {return details2.mesh.vertexCount-details1.mesh.vertexCount;});
		
	}

	private TextureDetails GetTextureDetail(Texture tTexture, Material tMaterial, MaterialDetails tMaterialDetails)
	{
		TextureDetails tTextureDetails = FindTextureDetails(tTexture);
		if (tTextureDetails == null)
		{
			tTextureDetails = new TextureDetails();
			tTextureDetails.texture = tTexture;
			tTextureDetails.isCubeMap = tTexture is Cubemap;

			int memSize = CalculateTextureSizeBytes(tTexture);

			tTextureDetails.memSizeKB = memSize / 1024;
			TextureFormat tFormat = TextureFormat.RGBA32;
			int tMipMapCount = 1;
			if (tTexture is Texture2D)
			{
				tFormat = (tTexture as Texture2D).format;
				tMipMapCount = (tTexture as Texture2D).mipmapCount;
			}
			if (tTexture is Cubemap)
			{
				tFormat = (tTexture as Cubemap).format;
			}

			tTextureDetails.format = tFormat;
			tTextureDetails.mipMapCount = tMipMapCount;
			
		}
		tTextureDetails.FoundInMaterials.Add(tMaterial);
		foreach (Renderer renderer in tMaterialDetails.FoundInRenderers)
		{
			if (!tTextureDetails.FoundInRenderers.Contains(renderer)) tTextureDetails.FoundInRenderers.Add(renderer);
		}
		return tTextureDetails;
	}	
}

相關推薦

Unity3D實用指令碼—— 檢查場景中用到的資源

在專案的開發過程中,經常需要檢查場景中所用到的資源,例如Textures,Materials,Meshs等。 今天來實現如圖所示的資源檢查功能。 程式碼如下: // Resource Checker // (c) 2012 Simon Oliver / HandCirc

iptables實用教程:管理鏈和策略

否則 命令顯示 accept 目的 number cep 存在 當前 末尾 概念和原理請參考上一篇文章“iptables實用教程(一)”。 本文講解如果管理iptables中的鏈和策略。 下面的代碼格式中,下劃線表示是一個占位符,需要根據實際情況輸入參數,不帶下劃線的表示是

Nginx實用教程:配置文件入門

affinity type 服務 源碼編譯 設置時間 shutdown ber 可用 控制指令 Nginx配置文件結構 nginx配置文件由指令(directive)組成,指令分為兩種形式,簡單指令和區塊指令。 一條簡單指令由指令名、參數和結尾的分號(;)組成,例如:

前端開發框架總結之Angular實用技巧

                                前端開發框架總結之Angular實用技巧(二) 上文講了Angular自

java調Python指令碼:java調Python亂碼問題

java調Python返回結果出現亂碼解決: Python指令碼編碼格式已經用了utf-8,但是返回還是亂碼,說明是java這邊傳過去編碼有問題。 1、Python編碼格式: 2、一般我們中文文字編碼格式常用的有:UTF-8,GBK,GB2312。分別試一下就知道了:

動態記憶體分配實用案例之複製字串

用動態分配記憶體製作一個字串的一份拷貝。注意:呼叫程式應該負責檢查這塊記憶體是否分配成功,這樣做允許程式以任何它所希望的方式對錯誤作出反應。 #nclude <stdlib.h> #include <string.h> char * strdup

床頭筆記之Python程式設計實用函式

python字典dict排序與sorted函式 sorted(iterable[, cmp[, key[, reverse]]]) 引數說明: iterable – 可迭代物件。 cmp --比較的函式,這個具有兩個引數,引數的值都是從可迭代物件中取出,此函

JAVA實用操作安裝旗艦版IDEA破解版

第二步:雙擊已下載檔案,進行開始安裝; 點選 next 繼續ing… 選擇適合本機的64位(32位)版本,點選next 繼續… 選擇預設繼續… 等待安裝完成…next 繼續ing… 以上操作就完成了ideal的安裝了 ~~~ 接下來就是實現解析工

如何編寫一個優雅的Shell指令碼

簡介 繼上一篇,本文主要描述一個shell指令碼的基本組成 公共模組 ## 自定義寫日誌函式 function writelog() { echo "[`date -d '%Y-%m-%d %H:%M:%S'`][$$]: $1" |tess -a $tmplogf

JVM實用引數引數分類和即時JIT編譯器診斷

在這個系列的第二部分,我來介紹一下HotSpot JVM提供的不同類別的引數。我同樣會討論一些關於JIT編譯器診斷的有趣引數。 JVM 引數分類 HotSpot JVM 提供了三類引數。第一類包括了標準引數。顧名思義,標準引數中包括功能和輸出的引數都是很穩定的,很可能在將來的JVM版本中不會

Linux系統下製作服務啟動指令碼

上一篇部落格介紹了在/etc/init.d目錄下製作應用服務啟動和停止指令碼,其實在/usr/bin目錄下也可以製作這種指令碼,不過一般不推薦這種方式,先來看一下是怎麼製作的: vim編寫指令碼start.sh,將指令碼複製到/usr/bin目錄下,去掉字尾名 然後進入任何目

自動化測試工具AutoRunner之錄製指令碼

這一篇主要講一下使用AutoRunner錄製指令碼的方法 一、建立專案: 建立專案的方式有兩種: 1、在專案區單擊滑鼠右鍵,彈出建立專案選單。 2、選中“ 新建專案”,開啟“新建專案”彈窗。 3、 輸入“專案名稱”,此處有兩個選項,我們以“不

ant自動打包指令碼

融合SDK ant自動打包指令碼,可以迴圈打包,採用源工程(主工程)和依賴庫的形式 <?xml version="1.0" encoding="UTF-8"?> <project name="AndroidProjectBuild" default="bu

建立一個簡單gradle指令碼

update time:2019-1-10 Author:要你命三千又三千 type: 學習筆記 文章目錄 問題一:如何是用gradle 搭建的環境建立一個簡單的Gradle指令碼 問題二:gradle Wrapp

OGRE的材質指令碼

Texture_unit 紋理單元我們在PASS渲染通道處已經進行了一次整體的渲染環境設定,然而,在每個紋理單元,我們還可以對單獨的紋理進行渲染屬性設定。 texture_alias 設定一個紋理的別名,類似於技術的別名。格式: texture_alias 紋理別名預設該別名

Android中的MVVM架構設計-實用

速度與激情7.jpg引言拖的時間夠久的了,趕緊來還債了...by the way...今天由於一些私人的關係,去了趟「大望路」的「小米體驗店」裡去體驗了一下,看到了剛剛釋出的的「小米8」,還有「小米8SE」,但是對我的感覺衝擊不是很大,不過 這兩部手機的速度肯定是沒得說的,價

spring boot 框架實用技巧初次上手

1.現在我們就開始上手一下spring boot 框架的使用。 學習任何框架我覺得最簡單的方式就是從它的事例上學習,還有個前提就是你至少以前學習過至少一種框架的使用,這樣的話上手會很快。 首先如上圖import spring 的專案選中spring getting sta

Installshield2008 And 指令碼

利用Script來控制其安裝流程的時候。最基本的就是 OnBegin ---------> OnShowUI OnShowUI裡面為:  OnFirstUIBefore  -----------> OnMoveData ------------------>

Unity3D學習筆記:個體層次、絕對和局部坐標、V3平移旋轉

esp 返回 ESS coo his object spa cti dcom Directional Light:平行光源/方向性光源,用來模擬太陽光(角度只與旋轉角度有關,與位置無關) Point Light:點光源,用來模擬燈泡,向四周發散光源 Spotlight:錐光

LoadRunner11錄製APP指令碼***利用WireShake進行抓包

前提:     1、安裝WireShark。在安裝WireShark過程中,會提示是否安裝WinPacp以及USBPacp。其中WinPacp必須安裝     2、電腦和手機必須處於同一網路