Unity3d 周分享(19期 2019.6.22 )

選自過去1~2周 自己所看到外文內容:https://twitter.com/unity3d 和各種其他博客來源吧 

1、 #UnityTips您知道OnOpenAsset屬性嗎? 它允許您在項目窗口中雙擊資源時調用方法。 例如可以用來打開/編輯一些scriptableobject。

 

2、https://www.febucci.com/2018/11/unity-tips-collection/

  1. Multiply Inspector’s editing speed
  2. Built-in shaders
  3. MinMax Attribute
  4. Animation Curves
  5. Un-dock the Preview window
  6. Hierarchy Organization
  7. Particle System Playback time
  8. EditorOnly tag
  9. Assign a shader to a material upon creation
  10. Insert array element in the Inspector
  11. Show the content of multiple folders
  12. Customize Unity’s C# template
  13. Console Window Log Entries
  14. OnValidate
  15. Set Editor Presets as Default
  16. Change the Editor color when it’s in Play Mode
  17. Drag/select scenes in the build settings
  18. Fold the entire Hierarchy
  19. Rich text in Unity’s console
  20. Asset Store search in project window
  21. DisallowMultipleComponent & RequireComponent
  22. Graphy
  23. Drag multiple items in the inspector
  24. Unity Visual Search
  25. NaughtyAttributes
  26. Foldout
  27. Scene Icons
  28. ContextMenu
  29. Inspector Math Expressions
  30. SerializeField & HideInInspector
  31. FormerlySerializedAs
  32. AddComponentMenu
  33. MenuItem

 

 

3、根據你們這麼多人的要求, 在@ Unity3d上製作了關於切割網格的教程

觀看完整的教程: https://www.youtube.com/watch?v=1UsuZsaUUng&feature=youtu.be

 

4、您是否正在#unity3d中的代碼中創建或修改網格? 我們可能會爲此計劃一些API改進,歡迎提供反饋。 請參閱google doc:Unity 2019.3 Mesh API Improvements https://docs.google.com/document/d/1I225X6jAxWN0cheDz_3gnhje3hWNMxTZq3FZQs5KqPc/edit#heading=h.vyksohcynwk5

和論壇帖子: https://forum.unity.com/threads/feedback-wanted-mesh-scripting-api-improvements.684670/

 

- 索引緩衝區Index buffers:手動指定整個索引緩衝區大小,從NativeArray設置完整或部分數據,手動設置子網格信息(拓撲,索引計數等)的能力。

- 頂點緩衝區Vertex buffers:能夠手動指定頂點緩衝區佈局(屬性數據格式,流分割),從NativeArray設置完整或部分數據。

- 添加到現有SetFoobar網格API的Slice-like(“int start,int length”)重載。

- 添加到現有網格索引API的ushort重載,以避免索引數據的32位< - > 16位轉換。

重要很重要的是 NativeArrays的重載目前非常受歡迎。

 

Problem: Unity中的Mesh腳本API是在Unity 1.5(即2006年!)中完成的,並且大部分保持不變。. 後來增加了一些 non-allocating List<T> 函數例如 (Mesh.SetVertices etc.),但整體API方法沒有改變。

它主要存在性能問題,額外的內存複製,內存分配以及無法指定更多自定義數據格式:

  • 頂點數據訪問基於各個屬性 (positions, normals etc.), 即使內部網格可能存儲它們也是交錯的。
  • 無法查詢或指定自定義頂點數據格式 (例如,對某些組件使用半精度float)
  • 索引緩衝區訪問全部基於32位索引,即使對於使用16位索引緩衝區的網格也是如此。
  • 無法對頂點/索引緩衝區數據進行部分更新;每次調用都會替換整個數組。
  • 使用基於NativeArray <T>的數據沒有很好的互操作性,這在C#Jobs / Burst / DOTS中很常見。

因此,在2019.3中,我們向Mesh類API添加了更多功能,在某種意義上,“更低級別”的API層更直接並且面向顯式索引/頂點緩衝區佈局和數據更新。

Let us know what you think about this! Here or on the forum thread.

 

Index Buffer API additions索引緩衝區API添加

(when: 本節中的所有內容都在進行中;尚未進行任何alpha版本)

指定索引緩衝區並更新它的數據:

void SetIndexBufferParams(int indexCount, IndexFormat format);
void SetIndexBufferData(
    NativeArray<T> data, int dataStart, int meshBufferStart, int count);

 

以上是用於設置索引緩衝區並使用數據填充/更新它。就像所有現有的Mesh API一樣,這適用於索引緩衝區的系統內存表示,例如,如果你做Mesh.GetIndices,將通過SetIndexBufferData完成更新。

當然僅僅指定索引緩衝區是不夠的,還必須設置網格“子網格submeshes”,其中基本上包含以下信息:: 邊界框bounding box, 面拓撲face topology, 索引緩衝區範圍index buffer range, 頂點緩衝區範圍vertex buffer range. Mesh類已經包含subMeshCount(默認爲1),除此之外:

struct SubMeshDescriptor
{
	AABB bounds;
	MeshTopology topology;
	int indexStart;
	int indexCount;
	int baseVertex;
	int firstVertex;
	int vertexCount;
};
void SetSubMesh(int index, SubMeshDescriptor desc);
SubMeshDescriptor GetSubMesh(int index);

通過上述組合,您可以完全控制索引緩衝區和網格子集信息。 SetIndexBufferParams可能(重新)爲緩衝區分配內存,SetIndexBufferData更新它(或它的一部分),數據與內存中的索引緩衝區佈局匹配,並且沒有格式轉換。 SetSubMesh可用於指定索引開始和計數,而無需調整大小或重新填充索引/頂點緩衝區。

 

Vertex Buffer API additions 頂點緩衝區API

(when: 本節中的所有內容都在進行中;尚未進行任何alpha版本)

需要指定頂點數據佈局:存在哪些屬性,它們的格式,通道數以及哪些屬性進入哪些流(一個流中的所有內容都是經典的“交錯interleaved”頂點佈局;但Unity也幾乎可以任意放置屬性進入各種流配置)。

enum VertexAttributeFormat
{
	Float32, Float16,
	UNorm8, SNorm8,
	UNorm16, SNorm16,
	UInt8, SInt8,
	UInt16, SInt16,
	UInt32, SInt32,
};
struct VertexAttributeDescriptor
{
	VertexAttribute attribute;
	VertexAttributeFormat format;
	int dimension;
	int stream;
};
VertexAttributeDescriptor[] GetVertexAttributes();
bool                        HasVertexAttribute(VertexAttribute a);
VertexAttributeFormat       GetVertexAttributeFormat(VertexAttribute a);
int                         GetVertexAttributeDimension(VertexAttribute a);
 
bool SystemInfo.SupportsVertexAttributeFormat(VertexAttributeFormat format,
    int dimension);
 
void SetVertexBufferParams(int vertexCount,
    params VertexAttributeDescriptor[] attributes);

以上內容可用於查詢網格數據佈局(已經可能對GetNativeVertexBufferPtr有用),或者用於顯式設置頂點緩衝區的大小和佈局。請注意,未指定頂點數據屬性的各個偏移量;目前在Unity中,它們總是被隱式計算爲以預定義的順序 (positions, normals, tangents, colors, texture coordinates, blend weights, blend indices)一個接一個地進行計算。

許多API /平臺要求頂點組件的大小爲4個字節的倍數,因此我們在SetVertexBufferParams級別強制執行此操作。例如: Float16 with dimension=3 is invalid (6 bytes), or UNorm8 with dimension=2 is invalid too.

使用NativeArray <T>源對每個流進行單獨調用來更新頂點數據,其中T是必須與頂點數據佈局匹配的結構(這可能意味着C#側的結構可能需要StructLayout(順序)屬性,也許有Pack字段設置)。

void SetVertexBufferData(
    NativeArray<T> data, int dataStart, int meshBufferStart, int count,
    int stream=0);

與SetIndexBufferData一樣,這會更新頂點緩衝區或其中一部分的系統內存表示,並且不會執行任何數據轉換。

 

Existing old-style API additions and other small things現有的舊式API 和其他小東西

(when: 本節中的所有內容都在2019.3 alpha 4中)

爲了保持一致性並且因爲它被請求,我們還爲現有的“舊”樣式Mesh API添加了更多重載。

頂點數據設置器(SetVertices,SetNormals等)具有 “切片式 slice-style” API,其使用所提供的陣列的一部分或列表用於新的頂點數據。所有頂點屬性 SetFoo(List<T>) API也得到:

  • SetFoo(T[])
  • SetFoo(T[], int start, int length)
  • SetFoo(List<T>, int start, int length)

類似地,索引數據設置器(SetTriangles和SetIndices)得到切片式重載:

  • SetIndices(int[] indices, int start, int length, …)
  • SetIndices(List<int> indices, int start, int length, …)

處理索引數據的現有函數在沒有額外轉換的情況下獲得了超載以處理16位索引:

  • Add ushort[] and List<ushort> overloads to SetIndices
  • Add ushort[] and List<ushort> overloads to SetTriangles
  • Add List<ushort> overload to GetIndices

對Mesh API各個部分的腳本文檔進行了調整,使其更加準確,詳細,並在更多地方提及其他相關API。

 

Not Done Yet, But We Are Thinking About It尚未完成,但我們正在思考它

將網格緩衝區用於計算着色器會很好。也許是以下列方式之一:

  • 可選的標誌,使網格緩衝區可以計算-writable/readable, 以及從網格中獲取ComputeBuffer或GraphicsBuffer的方法,或者
  • 一種從用戶提供的ComputeBuffer或GraphicsBuffer對象和一些額外信息創建 “外部external” Mesh的方法。類似於如何創建“外部”紋理。

 

直接NativeArray訪問網格頂點/索引緩衝區,沒有由SetVertexBufferData / SetIndexBufferData引起的memcpy。這可能與NativeArray Texture2D.GetRawTextureData的工作方式類似。

 

將“Flags”參數添加到SetVertexBufferParams / SetIndexBufferParams。可能包含以下標誌:

  • “Dynamic buffer”, replacing Mesh.MarkDynamic
  • “Compute”, see above wrt Compute Shader usage
  • “Keep/convert previous data”, try to convert previously existing data

將“Flags”參數添加到SetVertexBufferData / SetIndexBufferData。可能包含以下標誌:

  • “Update bounds”, optional automatic bounds calculation
  • “Check”, to validate if indices are not out of range (always done in old Mesh API)
  • “Update vertex ranges”, optional automatic SubMeshDescriptor vertex range calculation

 

 

5、

Unity 2018.3中的作業安全API

Unity 2019.1中的Job-Safe API

https://jacksondunstan.com/articles/5029

https://jacksondunstan.com/articles/5239

所以對於今天,我們現在有一個小的Unity編輯器腳本,它將爲我們生成列表。這是它的作用:

1查找.dllUnity安裝目錄的Managed子目錄中的所有文件

2打開它們作爲 Assembly

3掃描所有方法和屬性

4檢查[NativeMethod]屬性是否存在

5調用get給NativeMethodAttribute.IsThreadSafe

6輸出所有匹配項Debug.Log和系統剪貼板

2018.3高達301作業安全的API,但很多人都private還是internal ,因此必須通過一個間接調用public API。總而言之,自Unity 2018.2以來,它只是九種方法和屬性的擴展。但是,Unity越來越依賴於軟件包來提供新功能,例如當前處於預覽版的ECS。要使用此腳本檢查任何其他庫,只需更改paths變量以包含其目錄。

Unity 2019.1.3f1運行相同的腳本會生成350個函數的列表:

值得注意的是,其中許多功能都是私有或內部功能。許多人甚至在他們的名字中都有“內部”這個詞。雖然這些仍然可以通過反射在技術上調用,但更典型的方法是在公共API中調用某個函數,然後直接或間接地調用私有函數或內部函數。

找到如何調用這59個新的作業安全功能必須根據具體情況進行,但很容易看出引擎整體上變得更加安全。這對於Unity中高性能代碼的未來來說是一件好事,特別是現在我們擁有專門用於C#作業的Burst編譯器。

 

 

 

 

6、 ffmpeg stream raw video into unity Texture2D

ffmpeg將原始視頻流轉換爲Unity的Texture2D

下載 https://ffmpeg.zeranoe.com/builds/: Architecture Windows 64-bit

客戶端代碼: https://github.com/unitycoder/ffmpegStreamToUnity

運行Unity項目 。

然後命令行執行 :

 

unity項目,它應該顯示接收到的數據。 ffmpeg會捕獲桌面的內容 流式傳輸到Unity材質texture2D

接下來的步驟

- TCP版本可能修復丟失幀/不同步問題

- 使用正確的容器mpegts左右,修復udp遺漏幀等問題,但難以解碼mpeg4有效載荷數據

https://unitycoder.com/blog/2019/05/26/ffmpeg-stream-raw-video-into-unity-texture2d/

 

Unity 利用FFmpeg實現錄屏、直播推流、音頻視頻格式轉換、剪裁等功能

 

 

 

 

 

7、 爲着色器或腳本啓用HDR顏色選擇器

我需要一些舊的Unlit / Color-shader的HDR顏色,而對於c#腳本,也發現你可以爲着色器添加這個屬性:

// BEFORE (no hdr color picker)

_Color ("Main Color", Color) = (1,1,1,1)

// AFTER (hdr color picker)

[HDR]_Color ("Main Color", Color) = (1,1,1,1)

爲C#腳本:

// BEFORE

public Color shouldbeHDR = Color.white;

// AFTER

[ColorUsage(true, true)]

public Color shouldbeHDR = Color.white;

More info:

https://docs.unity3d.com/ScriptReference/ColorUsageAttribute.html

https://docs.unity3d.com/Manual/SL-Properties.html

還要確保您的相機啓用了[x] HDR

 

 

 

 

 

 

8、一個帖子 : https://forum.unity.com/threads/draw-signal-strength-scrolling-graph-with-a-shader.682465/ 使用着色器繪製模擬電波信號強度滾動圖...

基本思路:

- 使用CustomRenderTexture,雙緩衝,以便它可以自己讀取

- 將color32數組繪製到texture2D中

- 使用CustomRenderTexture中的texture2D作爲底部像素行

- CustomRenderTexture通過讀取下面的1個像素繼續向上滾動

滾動Perlin噪聲顏色(底部1像素行來自Texture2D)

https://github.com/unitycoder/ScrollingTexturePlotter

  • 使用 CustomRenderTexture 製作火特效

添加了火焰漸變顏色(通過將火焰計算移動到Alpha通道中)。

https://github.com/unitycoder/FireEffect

參考

 

 

 

9、 從Unity Build Files創建單個.EXE

使用Enigma Virtual Box

下載 : https://enigmaprotector.com/en/downloads.html

- 選擇輸入文件名:(這是Unity構建的.exe文件)

- 輸入輸出文件名:(這是輸出單個exe文件)*這必須與原始.exe文件名相同,以便找到Data文件夾。

- 單擊添加/添加文件夾遞歸..

- 瀏覽到您的Build文件夾,例如../Builds /在您的Unity項目中(Assets /文件夾旁邊)

- 現在您可以測試您的單個exe文件

- 注意:從StreamingAssets加載數據單個exe應用程序中的/文件夾似乎也可以工作。

如果包含exe和data文件夾,請選擇整個Builds文件夾

注: 另外, 測試此工具也有效,但似乎在運行exe時會打開控制檯窗口..

https://github.com/dgiagio/warp#windows-1

TODO

- 檢查enigma是否支持命令行參數,然後你可以使用一些編輯器腳本自動完成!

 

 

10、 Unity中角點檢測的快速算法

將此(基本)算法轉換爲Unity c#https://docs.opencv.org/3.0-beta/doc/py_tutorials/py_feature2d/py_fast/py_fast.html

快速(加速段測試的功能)是一種從圖像中檢測角落特徵的方法。

來源:*未優化

https://gist.github.com/unitycoder/7649f62a6eceeb761db7f0092d9c3df1

我的層次結構設置

 

 

 

11、 Unity中測試 Ray Marching

觀看了The Coding Train的這一集後,在Unity中測試了Ray Marching 光線行進。

? https://thecodingtrain.com/CodingChal... ?? https://editor.p5js.org/codingtrain/s... ? Website: http://thecodingtrain.com/ ? Patreon: https://patreon.com/codingtrain ? Store: https://www.designbyhumans.com/shop/c... ? Books: https://www.amazon.com/shop/thecoding... ? Coding Challenges: https://www.youtube.com/playlist?list... ? Intro to Programming: https://www.youtube.com/playlist?list... ?? p5.js: https://p5js.org ? Processing: https://processing.org

源代碼:https //gist.github.com/unitycoder/7120e492deba748dba3d4e1e424d3c2a

用法:

將相機設置爲0,0,-10

投影:正交

然後將球體置於空遊戲對象下,球體z值爲0

 

 

 

 

12、從顏色數組創建漸變紋理

用於從顏色數組生成漸變Texture2D的小工具。(注意:最大顏色數爲8,因爲它在內部使用單位漸變(https://docs.unity3d.com/ScriptReference/Gradient.html

來源:

https //github.com/UnityCommunity/UnityLibrary/blob/master/Assets/Scripts/Texture/GradientTextureMaker.cs

示例用法腳本:(將腳本附加到某些3d對象)

https://gist.github.com/unitycoder / f7ea9019bb67b7042efbd08f0f4fa785

Unity腳本,根據輸入`AnimationCurve`生成均勻分佈的`Gradient`的多個變體。

https://github.com/5argon/GradientGenerator

 

 

 

13、 [Unity] [編輯器擴展]當從Inspector增加序列化數組的元素數量時,防止複製元素。

如下圖正常情況下,新增加的元素內容是第一個元素的拷貝。

想在的需求是不希望這樣!

public class ElementBehaviour : MonoBehaviour

{

}

public class Example : MonoBehaviour

{

[SerializeField]

private ElementBehaviour[] _elements;

}

[CustomPropertyDrawer(typeof(ElementBehaviour))]

public class ElementBehaviourDrawer : PropertyDrawer

{

public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)

{

// 路徑是_elements.Array.data [x]

var splitPath = property.propertyPath.Split('.');

var isArrayElement = splitPath[splitPath.Length - 2] == "Array";

if (isArrayElement && property.objectReferenceValue != null) {

// 獲取數組索引

var arrayIndexStr = splitPath[splitPath.Length - 1].Replace("data[", "").Replace("]", "");

var arrayIndex = int.Parse(arrayIndexStr);

// 創建字符串_elements.Array.data [{0}]

var formatSplitPath = splitPath;

formatSplitPath[formatSplitPath.Length - 1] = "data[{0}]";

var formatPath = string.Join(".", formatSplitPath);

// 獲取上一個元素和下一個元素

var previousElementPath = string.Format(formatPath, arrayIndex - 1);

var nextElementPath = string.Format(formatPath, arrayIndex + 1);

var previousElement = property.serializedObject.FindProperty(previousElementPath);

var nextElement = property.serializedObject.FindProperty(nextElementPath);

var isLastElement = nextElement == null;

// 如果有前一個元素,並且最後一個元素(剛添加的元素),以及前一個元素和引用一樣,則刪除引用

if (arrayIndex >= 1 && isLastElement && previousElement.objectReferenceValue == property.objectReferenceValue) {

property.objectReferenceValue = null;

}

}

// 通常繪製屬性

using (new EditorGUI.PropertyScope(position, label, property)) {

EditorGUI.PropertyField(position, property);

}

}

public override float GetPropertyHeight(SerializedProperty property, GUIContent label)

{

return EditorGUIUtility.singleLineHeight;

}

}

當繪製元素時,它會檢查數組元素,以及刪除引用的過程(如果最後一個數組元素和前一個元素具有相同的引用)

 

 

 

 

14、 Unity中的代碼文件默認是 帶BOM 的 UTF-8

順便說一下,換行代碼根據OS而不同。

mac主要是LF,Windows是CR + LF (\r+ \n)。 Unity的換行代碼是CR + LF。即使它是LF也可能沒問題,但如果CR + LF文件和LF文件混合,則會出現不便,例如通過更改版本控制中的換行代碼就會出現差異。 此外,如果多個人在不同Unity代碼的環境中進行開發,則可以將換行代碼混合在一個文件中。 這是一個重要問題,因爲它會導致StackTrace行號不正確和編譯警告。

可以保證模板是正確的格式 : C:\ Program Files(x86)\ Unity \ Editor \ Data \ Resources \ ScriptTemplates

 

可以後處理 生成新腳本時將文本編碼轉換爲UTF-8 https://github.com/sharkattack51/GarageKit_for_Unity/blob/master/UnityProject/Assets/__ProjectName__/Editor/AssetPostprocessUTF8Encode.cs

獲取此處使用的文件編碼的部分作爲參考。

http://dobon.net/vb/dotnet/string/detectcode.html

 

 

 

15、 [Unity]輕鬆可視化網格信息(UV,頂點顏色,法線等)

有時您想要可視化網格所具有的信息,例如UV,頂點顏色和法線。

我所要做的就是寫一個着色器,但我把它變成了一個多功能的東西,因爲每次寫作都很麻煩。寫一個着色器。

Shader "Hidden/MeshInfoViewer"
{
    Properties
    {
        [KeywordEnum(UV0, UV1, VertexColorRGB, VertexColorAlpha, WorldNormal)]_MeshInfo("Mesh Info", float)     = 0
    }
    SubShader
    {
        Pass
        {
            CGPROGRAM
           #pragma vertex vert
           #pragma fragment frag
           #pragma multi_compile _MESHINFO_UV0 _MESHINFO_UV1 _MESHINFO_VERTEXCOLORRGB _MESHINFO_VERTEXCOLORALPHA _MESHINFO_WORLDNORMAL
            
           #include "UnityCG.cginc"
            struct appdata
            {
                float4 vertex       : POSITION;
                float2 texcoord0    : TEXCOORD0;
                float2 texcoord1    : TEXCOORD1;
                float4 color        : COLOR;
                float4 normal       : NORMAL;
            };
            struct v2f
            {
                float4 vertex       : SV_POSITION;
                float2 uv0          : TEXCOORD0;
                float2 uv1          : TEXCOORD1;
                float4 color        : COLOR;
                float3 normal       : NORMAL;
            };
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex    = UnityObjectToClipPos(v.vertex);
                o.uv0       = v.texcoord0;
                o.uv1       = v.texcoord1;
                o.color     = v.color;
                o.normal    = UnityObjectToWorldNormal(v.normal);
                return o;
            }
            fixed4 frag (v2f i) : SV_Target
            {
               #if _MESHINFO_UV0
                    return fixed4(i.uv0.xy, 0, 1);
               #elif _MESHINFO_UV1
                    return fixed4(i.uv1.xy, 0, 1);
               #elif _MESHINFO_VERTEXCOLORRGB
                    return fixed4(i.color.rgb, 1);
               #elif _MESHINFO_VERTEXCOLORALPHA
                    return fixed4(i.color.aaa, 1);
               #elif _MESHINFO_WORLDNORMAL
                    return fixed4(i.normal, 1);
               #endif
                return 1;
            }
            ENDCG
        }
    }
}

這個過程很簡單。

我爲每個要顯示的信息定義一個關鍵字並製作變體。

怎麼用

至於如何使用,只需從Inspector設置材質的模式。

http://light11.hatenadiary.com/entry/2018/12/03/224659

 

 

16、 [Unity] [編輯器擴展]在場景視圖中顯示窗口

這是一種在場景視圖中顯示IMGUI窗口的方法。

using UnityEngine;
using UnityEditor;
using UnityEngine.SceneManagement;
public class SampleSceneEditWindow {
    private static Rect _windowSize = new Rect(8, 24, 300, 100);
    private static bool _enabled = false;
    // 加載腳本時調用
    [InitializeOnLoadMethod]
    private static void SampleSceneEdit(){
        SceneView.onSceneGUIDelegate += OnSceneGUI;
    }
    private static void OnSceneGUI(SceneView sceneView){
        if (!GetIsTargetScene()) {
            return;
        }
        GUILayout.Window(1, _windowSize, DrawWindow, "Sample Window");
    }
    public static void DrawWindow(int id)
    {
        EditorGUILayout.LabelField("Sample");
    }
    private static bool GetIsTargetScene()
    {
        return SceneManager.GetActiveScene().name.Contains("sample_");
    }
}

 

 

17、 [Unity] [編輯器擴展]獲取特定資產的AssetImporter

https://docs.unity3d.com/ScriptReference/AssetImporter.html

這樣做的方法是將資產路徑傳遞給AssetImporter.GetAtPath() 。

Texture2D texture;

var importer = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(texture)) as TextureImporter;

類型是以下三種之一。

  • ModelImporter
  • TextureImporter
  • AudioImporter

基本用法:PreProcess和PostProcess

PreProcess方法。

  • OnPreprocessModel
  • OnPreprocessAudio
  • OnPreprocessAnimation
  • OnPreprocessSpeedTree
  • OnPreprocessTexture

Post也以各種方式定義。

  • OnPostprocessModel
  • OnPostprocessAudio
  • OnPostprocessSprites
  • OnPostprocessSpeedTree
  • OnPostprocessGameObjectWithUserProperties
  • OnPostprocessAssetbundleNameChanged
  • OnPostprocessTexture

這些Processor在以下時間進行。

  • 首先導入
  • Reimport時
  • 重命名時
  • 從Inspector更改設置並Apply時

導入所有資源後調用OnPostprocessAllAssets()方法。

此外,它晚於PostprocessXXX系列。

例如,如果選擇並重新導入兩個紋理,則在調用OnPostprocessTexture兩次後將調用一次OnPostprocessAllAssets。

 

GetPostprocessOrder()決定處理順序 ,此值似乎不會影響OnPostprocessAllAssets()。

如果創建多個繼承AssetPostprocessor的類,則可以通過定義GetPostprocessOrder()來確定處理順序。

值按升序處理。

public class AssetPostProcessorTest : AssetPostprocessor {
    public override int GetPostprocessOrder()
    {
        return 1;
    }
    private void OnPreprocessTexture()
    {
        Debug.Log(GetPostprocessOrder());
    }
    private void OnPostprocessTexture(Texture2D tex)
    {
        Debug.Log(GetPostprocessOrder());
    }
}
public class AssetPostProcessorTest2 : AssetPostprocessor {
    public override int GetPostprocessOrder()
    {
        return 2;
    }
    private void OnPreprocessTexture()
    {
        Debug.Log(GetPostprocessOrder());
    }
    private void OnPostprocessTexture(Texture2D tex)
    {
        Debug.Log(GetPostprocessOrder());
    }
}

您可以使用GetVersion()來定義版本。使用 GetVersion()進行版本控制

當版本更改時,該後處理器的處理將在所有資產上運行。

public class AssetPostProcessorTest : AssetPostprocessor {
    public override uint GetVersion()
    {
        return 1;
    }
    private void OnPreprocessTexture()
    {
        Debug.Log(assetPath);
    }
}

順便說一下,似乎從Unity2018添加了OnPreprocessAsset()。

 

 

 

 

 

 

18、 【YAML】YAML的基本語法

序列(數組)
- a
- b
- c
     結果由json表示如下:
[
  "a", 
  "b", 
  "c"
]
映射(字典)
A: a
B: b
C: c
對應Json如下
{
  "A": "a", 
  "B": "b", 
  "C": "c"
}
嵌套序列
- a
- b
-
 - c
 - d
對應Json如下
[
  "a", 
  "b", 
  [
    "c", 
    "d"
  ]
]
嵌套映射
A: a
B: b
C:
 1: c-1
 2: c-2
對應Json如下
{
  "A": "a", 
  "B": "b", 
  "C": {
    "1": "c-1", 
    "2": "c-2"
  }
}
映射序列
- A: a
  B: b
- C: c
  D: d
對應Json如下
[
  {
    "A": "a", 
    "B": "b"
  }, 
  {
    "C": "c", 
    "D": "d"
  }
]
序列映射
A: 
 - a-1
 - a-2
 - a-3
B:
 - b-1
 - b-2
對應Json如下
{
  "A": [
    "a-1", 
    "a-2", 
    "a-3"
  ], 
  "B": [
    "b-1", 
    "b-2"
  ]
}

包含換行符的字符串
A: |
 line1
 line2
 line3
對應Json如下
{
  "A": "line1\nline2\nline3"
}
錨定別名
您可以使用&[Anchor Name]註冊錨點,如下所示,並使用* [Anchor Name]引用它。
- &test a
- b
- c
- *test
對應Json如下
[
  "a", 
  "b", 
  "c", 
  "a"
]
錨也附加到序列和映射。
- a
- b
- &c
 - c-1
 - c-2
- *c
你可以用它來做這樣的事情。
players: 
 - &profile1
  id: 1
  name: taro
  age: 21
 - &profile2
  id: 2
  name: hanako
  age: 18
currentPlayer : *profile1
對應Json如下
{
  "players": [
    {
      "age": 21, 
      "id": 1, 
      "name": "taro"
    }, 
    {
      "age": 18, 
      "id": 2, 
      "name": "hanako"
    }
  ], 
  "currentPlayer": {
    "age": 21, 
    "id": 1, 
    "name": "taro"
  }
}
還有一種稱爲流式的書寫方法
[A, B, C: c]
對應Json如下
[
  "A", 
  "B", 
  {
    "C": "c"
  }
]
  • 序列(數組)

- a - b - c

結果由json表示如下:

[ "a", "b", "c" ]

  • 映射(字典)

A: a B: b C: c

對應Json如下

{ "A": "a", "B": "b", "C": "c" }

  • 嵌套序列

- a - b - - c - d

對應Json如下

[ "a", "b", [ "c", "d" ] ]

  • 嵌套映射

A: a B: b C: 1: c-1 2: c-2

對應Json如下

{ "A": "a", "B": "b", "C": { "1": "c-1", "2": "c-2" } }

  • 映射序列

- A: a B: b - C: c D: d

對應Json如下

[ { "A": "a", "B": "b" }, { "C": "c", "D": "d" } ]

  • 序列映射

A: - a-1 - a-2 - a-3 B: - b-1 - b-2

對應Json如下

{ "A": [ "a-1", "a-2", "a-3" ], "B": [ "b-1", "b-2" ] }

在YAML中,類型是自動確定的。

例子

類型判定

1 / 1,000

int

0.1

float

true・false / yes・no

bool

"text" / 'text'

string

~ / null

null

2019-01-01

日期

2020-01-01 00:00:00 +00:00

時間戳

 

  • 包含換行符的字符串

A: | line1 line2 line3

對應Json如下

{ "A": "line1\nline2\nline3" }

  • 錨定別名

您可以使用&[Anchor Name]註冊錨點,如下所示,並使用* [Anchor Name]引用它。

- &test a - b - c - *test

對應Json如下

[ "a", "b", "c", "a" ]

錨也附加到序列和映射。

- a - b - &c - c-1 - c-2 - *c

你可以用它來做這樣的事情。

players: - &profile1 id: 1 name: taro age: 21 - &profile2 id: 2 name: hanako age: 18 currentPlayer : *profile1

對應Json如下

{ "players": [ { "age": 21, "id": 1, "name": "taro" }, { "age": 18, "id": 2, "name": "hanako" } ], "currentPlayer": { "age": 21, "id": 1, "name": "taro" } }

  • 還有一種稱爲流式的書寫方法

[A, B, C: c]

對應Json如下

[ "A", "B", { "C": "c" } ]

  • 一個易於試用的網站

以下網站便於輕鬆嘗試YAML語法。它將YAML解析爲json和python。

http://yaml-online-parser.appspot.com/

http://ben-kiki.org/ypaste/

 

 

【Unity】打開Prefab或Scene YAML並直接編輯

包括可能是 ScriptableObject 對象, 在Unity中直接修改原始文件可能更方便, 比如字符串替換一下。 省去了寫代碼邏輯。 比如在 VS Code這種文本編輯器中批量處理就很方便。

Unity2018.3.6, 嘗試在文本編輯器中打開一個空的GameObject 。

%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &4903041867623032639
GameObject:
  m_ObjectHideFlags: 0
  m_CorrespondingSourceObject: {fileID: 0}
  m_PrefabInstance: {fileID: 0}
  m_PrefabAsset: {fileID: 0}
  serializedVersion: 6
  m_Component:
  - component: {fileID: 4433608277066839807}
  m_Layer: 0
  m_Name: GameObject (1)
  m_TagString: Untagged
  m_Icon: {fileID: 0}
  m_NavMeshLayer: 0
  m_StaticEditorFlags: 0
  m_IsActive: 1
--- !u!4 &4433608277066839807
Transform:
  m_ObjectHideFlags: 0
  m_CorrespondingSourceObject: {fileID: 0}
  m_PrefabInstance: {fileID: 0}
  m_PrefabAsset: {fileID: 0}
  m_GameObject: {fileID: 4903041867623032639}
  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
  m_LocalPosition: {x: -0.21204466, y: 0.30996525, z: -0.86567664}
  m_LocalScale: {x: 1, y: 1, z: 1}
  m_Children: []
  m_Father: {fileID: 0}
  m_RootOrder: 0
  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}

前兩行是標準形式, 每個都有。

組成Prefab 的每個類(GameObject或組件)的信息由 --- 分隔。

     --- !u!1 &4903041867623032639
     GameObject:

這之後的數字!u!是類ID。下一行的字符串是類名。

這些定義如下。順便說一句,我所有的類都是114:MonoBehaviour。

此外,&之後的數字是表示此Prefab中的此GameObject或組件的任意ID。

比如可以修改 localScale 的值:

  m_LocalScale: {x: 2, y: 2, z: 2}

添加一個如下組件:

public class Example : MonoBehaviour
{
    [SerializeField]
    private int _example;
}

YAML 變爲如下:

%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &4903041867623032639
GameObject:
  m_ObjectHideFlags: 0
  m_CorrespondingSourceObject: {fileID: 0}
  m_PrefabInstance: {fileID: 0}
  m_PrefabAsset: {fileID: 0}
  serializedVersion: 6
  m_Component:
  - component: {fileID: 4433608277066839807}
  - component: {fileID: 5697825174949230319}
  m_Layer: 0
  m_Name: GameObject
  m_TagString: Untagged
  m_Icon: {fileID: 0}
  m_NavMeshLayer: 0
  m_StaticEditorFlags: 0
  m_IsActive: 1
--- !u!4 &4433608277066839807
Transform:
  m_ObjectHideFlags: 0
  m_CorrespondingSourceObject: {fileID: 0}
  m_PrefabInstance: {fileID: 0}
  m_PrefabAsset: {fileID: 0}
  m_GameObject: {fileID: 4903041867623032639}
  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
  m_LocalPosition: {x: -0.21204466, y: 0.30996525, z: -0.86567664}
  m_LocalScale: {x: 1, y: 1, z: 1}
  m_Children: []
  m_Father: {fileID: 0}
  m_RootOrder: 0
  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &5697825174949230319
MonoBehaviour:
  m_ObjectHideFlags: 0
  m_CorrespondingSourceObject: {fileID: 0}
  m_PrefabInstance: {fileID: 0}
  m_PrefabAsset: {fileID: 0}
  m_GameObject: {fileID: 4903041867623032639}
  m_Enabled: 1
  m_EditorHideFlags: 0
  m_Script: {fileID: 11500000, guid: 041e1384a28babc438abff5eaa04bfe5, type: 3}
  m_Name: 
  m_EditorClassIdentifier: 
  _example: 0

換句話說,您似乎可以通過執行此過程來附加組件

因此,我將嘗試附加與試驗相同的組件

首先,在原來基礎上 將先前添加的組件部分複製到底部。僅更改ID。

  - component: {fileID: 5697825174949230320}
--- !u!114 &5697825174949230320
MonoBehaviour:
  m_ObjectHideFlags: 0
  m_CorrespondingSourceObject: {fileID: 0}
  m_PrefabInstance: {fileID: 0}
  m_PrefabAsset: {fileID: 0}
  m_GameObject: {fileID: 4903041867623032639}
  m_Enabled: 1
  m_EditorHideFlags: 0
  m_Script: {fileID: 11500000, guid: 041e1384a28babc438abff5eaa04bfe5, type: 3}
  m_Name: 
  m_EditorClassIdentifier: 
  _example: 0

知道如何添加了, 那麼移除自然就很簡單, 你可以試一試 ~~

與此同時,讓我們看看除了預製件之外的YAML。

Scene的YAML。 它看起來很複雜,因爲有很多設置項,但格式與Prefab相同。 自己看吧 ~~~

接下來,我們來看看ScriptableObject 的YAML。

%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
  m_ObjectHideFlags: 0
  m_CorrespondingSourceObject: {fileID: 0}
  m_PrefabInstance: {fileID: 0}
  m_PrefabAsset: {fileID: 0}
  m_GameObject: {fileID: 0}
  m_Enabled: 1
  m_EditorHideFlags: 0
  m_Script: {fileID: 11500000, guid: 37c88262b3fdee44da78122d1afd7476, type: 3}
  m_Name: ScriptableObject
  m_EditorClassIdentifier: 
  _example: 0

這不是GameObject,它比Prefab簡單。格式與Prefab相同。

 

Text-Based Scene Files

 

 

 

19、 [Unity] [編輯器擴展] 在組件中設置HideFlags的問題, 它在成爲預製件時消失

在組件上設置HideFlags可以在Inspector中隱藏它。(因爲它是UnityEngine.Object的一個屬性,它可以在組件之外使用)

現在假設您使用它來防止組件從Inspector中可見。

 

解決方案是在MonoBehaviour的OnValidate()中設置hideFlags。

using UnityEngine;
public class Example : MonoBehaviour
{
    private void OnValidate()
    {
        hideFlags |= HideFlags.HideInInspector;     // | 運算 ,添加了標誌而不是被覆蓋。
    }
} 

雖然不顯示, 但是依然存在, 也會保存到Prefab中:

可以在此處理預製生成/更新的回調,因爲它們可以按如下方式進行處理。

using UnityEditor;
using UnityEngine;
[InitializeOnLoad]
public class OnPrefabInstanceUpdated
{
    static OnPrefabInstanceUpdated()
    {
        PrefabUtility.prefabInstanceUpdated += OnPrefabInstanceUpdate;
    }
    private static void OnPrefabInstanceUpdate(GameObject instance)
    {
        // 預製件實例的組件
        var instanceComponents = instance.GetComponentsInChildren<MonoBehaviour>();
        foreach (var instanceComponent in instanceComponents) {
            // 預製組件
            var prefabComponent = PrefabUtility.GetCorrespondingObjectFromOriginalSource(instanceComponent);
            // 此時,instanceComponent的hideFlags已更改爲None,因此下面的代碼沒有意義
            prefabComponent.hideFlags = instanceComponent.hideFlags;
            // 即使以這種方式,它也沒有被反映出來
            if (instanceComponent.GetType() == typeof(Example) || instanceComponent.GetType().IsSubclassOf(typeof(Example))) {
                prefabComponent.hideFlags |= HideFlags.HideInInspector;
            }
        }
    }
}

但是,如評論中所述,此方法效果不佳。

HideFlags 果然很有意思 ~~~

 

 

20、 [Unity]在TextMesh Pro中使用Mobile 版本着色器

針對移動平臺,肯定是推薦優先使用這些~

 

21、 使用反射調用BuildAndRun

[MenuItem("ReflectionTest/BuildAndRun")]
public static void BuildAndRun() 
{   
    // 方法名稱可能會根據Unity版本而改變...
    var reflectionMethodName = "CallBuildMethods";
    var reflectionFlags =  BindingFlags.NonPublic | BindingFlags.Static;

    var buildAndRun = typeof(BuildPlayerWindow).GetMethod(reflectionMethodName, reflectionFlags);

    if(buildAndRun != null){
        // 注意UnityEngine.Object的錯誤。
        buildAndRun.Invoke(null, new System.Object[]{ true, BuildOptions.AutoRunPlayer | BuildOptions.StrictMode });
    }
}

 

 

22、 首先GPU Profiler並不是所有圖形API和顯卡都能支持的,如果不支持面板中會提示。還有如果打開了 Graphics Jobs (Experimental) 選項,GPU Profiler將會被關閉。

首先來看看各平臺GPU Profiler所支持的圖形API和顯卡。

 

 

23、

Project Tiny C# Preview available Tiny Project的 C#版本現在可以使用了, 之前是Typescript版本的~~~

https://forum.unity.com/threads/project-tiny-c-preview-available.688969/?from=timeline

Unity’s Data-Oriented Tech Stack (DOTS)

我們非常高興能與您分享使用C#作爲編程語言的新Project Tiny的第一個預覽版。我們一直在努力改變大多數爲Project Tiny提供支持的基礎技術,以響應您的反饋,並使其更接近Unity生態系統。此預覽與Unity的面向數據的技術堆棧(DOTS)完全集成,併爲爲小型和大型用例提供高級功能奠定了基礎。

使用Unity 2019.2.0b3或更高版本,您可以立即通過軟件包管理器安裝“Project Tiny Preview - 0.15.3”。有關詳細信息,請參閱下面的“入門”。

 

 

 

 

 

24、 中國官方翻譯:

https://connect.unity.com/p/zai-bian-ji-qi-gong-ju-zhong-kuai-su-ti-qu-lei-xing-shu-xing

 

UnityEditor.TypeCache API,用於在編輯器工具中快速提取類型屬性

https://forum.unity.com/threads/unityeditor-typecache-api-for-fast-extraction-of-type-attributes-in-the-editor-tooling.687682/?utm_source=twitter&utm_medium=social&utm_campaign=engine_global_generalpromo_2019-06-04_2019-2-beta&utm_content=forum+thread

您正在開發編輯器實用程序或包嗎? Unity 2019.2 beta公開了一種用於類型提取的新API,以減少工具初始化並進入播放模式時間。

爲什麼會出現性能問題

在考慮優化進入Play模式時,我們發現從加載的程序集中提取類型需要相當長的時間。類型提取在編輯器模塊內部廣泛使用,在外部由包和用戶代碼使用,以擴展編輯功能。累積效果取決於項目,並且可以爲域重新加載時間貢獻300-600毫秒(如果系統具有延遲初始化,則可以更多)。在新的Mono運行時,由於時間的原因,時間顯着增加Type.IsSubclassOf性能迴歸,最長可達1300毫秒。

性能問題源於這樣一個事實:代碼通常從當前域中提取所有類型,然後迭代所有類型進行昂貴的檢查。時間根據遊戲類型的數量線性增加(通常爲30-60K)。

解決方案

緩存類型信息允許我們打破由域中的類型的迭代引起的O(N)複雜性。在本機級別,我們已經有了加速結構,它們在加載所有程序集後填充幷包含緩存類型數據,例如方法和類屬性以及接口實現程序。在內部,這些結構通過UnityEditor.EditorAssemblies API公開,以利用快速緩存。遺憾的是,API未公開發布,並且不支持重要的SubclassesOf用例。

對於2019.2,我們優化並擴展了本機緩存,並將其作爲公共UnityEditor.TypeCache API公開。它可以非常快速地提取信息,允許迭代我們感興趣的較少數量的類型(10-100)。這大大減少了通過編輯器工具獲取類型所需的時間。

具體示例代碼看論壇 :::::

 

 

 

25、

NEW 2D LIGHTS IN UNITY 2019.2 (Tutorial)

https://forum.unity.com/threads/experimental-2d-lights-and-shader-graph-support-in-lwrp.683623/

https://www.youtube.com/watch?v=ZJvCphxCGJU

我們在LWRP的實驗命名空間中發佈了一個2D渲染器。

此版本包括:

  • 2D燈
  • 着色器圖中的點亮和未點亮的Sprite Masternode
  • Pixel Perfect相機組件
    • 這將是Pixel Perfect前進的新家。獨立包仍然會收到錯誤修復,但只會在此處添加新功能。
    • 這是與Pixel Perfect軟件包中的工作流程相同的組件。主要變化是Pixel Perfect現在與LWRP中的2D渲染器兼容。

樣本

在此處獲取2D渲染器示例:

https//github.com/Unity-Technologies/2d-renderer-samples

文檔: https://docs.unity3d.com/Packages/[email protected]/manual/2d-index.html

 

 

 

26、

Unity Roadmap - Q2 - 2019.pdf 最新版本 :

正如一些人提出的那樣,最新更新的#Unity路線圖 第二季是https://www.dropbox.com/s/bj8l1s7meiw00dj/Roadmap%20-%20Q2%20-%202019.pdf?dl=0 ... #gamedev - 如果你看到的話,自GDC以來只有一些小的更新。

https://www.dropbox.com/s/bj8l1s7meiw00dj/Roadmap%20-%20Q2%20-%202019.pdf?dl=0

推薦看一下 , 推薦看一下 , 推薦看一下 ,

 

 

 

 

27、 [Unity]在使用adb shell am start啓動Android應用程序時分析指定參數的“Uni Android Intent”函數已發佈到GitHub

https://github.com/baba-s/uni-android-intent

Unity 2018.3.11f1

adb shell am start ^
    -n com.baba_s.uniandroidintent/com.unity3d.player.UnityPlayerActivity ^
    --ei i 123 ^
    --el l 456 ^
    -e s ABC ^
    --ez b true ^
    --eia ia 111,223,343 ^
    --ela la 444,555,666 ^
    --esa sa AAA,BBB,CCC

如果您使用adb shell am start啓動帶有參數的Android應用程序

// int 類型值獲取
Debug.Log( UniAndroidIntent.GetInt( "i" ) );
// long 類型值獲取
Debug.Log( UniAndroidIntent.GetLong( "l" ) );
// string 類型值獲取
Debug.Log( UniAndroidIntent.GetString( "s" ) );
// bool 類型值獲取
Debug.Log( UniAndroidIntent.GetBool( "b" ) );
// int 數組類型值獲取
foreach ( var n in UniAndroidIntent.GetIntArray( "ia" ) )
{
    Debug.Log( n );
}
// long 數組類型值獲取
foreach ( var n in UniAndroidIntent.GetLongArray( "la" ) )
{
    Debug.Log( n );
}
// string 數組類型值獲取
foreach ( var n in UniAndroidIntent.GetStringArray( "sa" ) )
{
    Debug.Log( n );
}

您可以使用此類代碼解析和使用參數

如何爲adb shell指定參數

類型

指定方法

int

--ei [參數名稱] [參數值]

long

--el [參數名稱] [參數值]

string

-e [參數名稱] [參數值]

bool

--ez [參數名稱] [參數值]

int 數組

--eia [參數名稱] [數組的值(以逗號分隔)]

long 數組

--ela [參數名稱] [數組的值(以逗號分隔)]

string 數組

--esa [參數名稱] [數組的值(以逗號分隔)]

用途:::

例如, 在使用Jenkins等自動構建應用程序並 進一步執行測試之後,通過在Android設備上自動安裝應用程序 來檢查構建的應用程序是否正常工作

https://developer.android.com/reference/android/content/Intent

 

 

 

 

28、 [Unity]可以從Inspector更改着色器的剔除模式

Shader "Unlit/NewUnlitShader"
{
    Properties
    {
        [Enum(UnityEngine.Rendering.CullMode)] _Cull("Cull", Float) = 0 // ★
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100
        Pass
        {
            Cull [_Cull] // ★
            CGPROGRAM
。。。。。。。

切換後就可以看到效果。

  1. 指定[Enum(UnityEngine.Rendering.CullMode)]作爲屬性
  2. 指定 Cull [_Cull]

 

 

 

29、 [Unity]如何在着色器的Inspector中顯示和使用開關

Shader "Unlit/NewUnlitShader"
{
    Properties
    {
        [Toggle(IS_RED)] _IsRed("Is Red", Float) = 0 // ★
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_fog
            #pragma shader_feature _ IS_RED // ★

            #include "UnityCG.cginc"
。。。。。。。。。。。。。。。

1、指定Toggle爲屬性

2、使用#pragma shader_feature指定關鍵字

3、在#if中使用關鍵字

 

 

30、

怎麼爲角色創建 LodGroup ?

https://answers.unity.com/questions/323575/creating-lod-group-for-character.html

 

 MySoldier (GameObject with LOD Group)

    Soldier_LOD0 (with Animation)

       Pelvis

          other bones

       Soldier (SkinnedMeshRenderer)

    Soldier_LOD1 (with Animation)

       Pelvis

          other bones

       Soldier (SkinnedMeshRenderer)

 

結果是網格將在距離處切換,但除非我將動畫應用於Soldier_LOD0和Soldier_LOD1,否則不會進行動畫處理。

有沒有人對Olly在幾個LOD上製作動畫角色的步驟有什麼好運?

我懷疑fbx需要包含單個骨架和多個蒙皮網格,但是如果有人對如何從包含單個蒙皮網格的多個fbx設置它們有任何建議,那麼我真的很感激如何實現這一點的一些信息。

https://forum.unity.com/threads/level-of-detail-management-lod.7265/

如果Lod 只是切換Mesh !!!

它所做的只是改變Mesh用於顯示一個角色。遊戲對象根本不會改變或切換。

所以動畫應該正常工作,腳本應該繼續運行等等; 它所做的就是改變使用哪個網格。您只需更改MeshFilter組件中使用的網格即可。

var highLod : Mesh;
var lowLod : Mesh;
var distance = 10.0;
function Update ()
{
    var campos = Camera.main.transform.position;
    var meshFilter : MeshFilter = GetComponent(MeshFilter);
    if( (transform.position - campos).sqrMagnitude <
        distance * distance )
    {
        // use high LOD
        if( meshFilter.sharedMesh != highLod )
            meshFilter.sharedMesh = highLod;
    }
    else
    {
        // use low LOD
        if( meshFilter.sharedMesh != lowLod )
            meshFilter.sharedMesh = lowLod;
    }
}

https://docs.unity3d.com/2019.1/Documentation/Manual/LevelOfDetail.html

https://docs.unity3d.com/2019.1/Documentation/Manual/class-LODGroup.html

 

 

 

 

31、[ReSharper]關於如何使用ReSharper的文章摘要(75)

 

 

 

32、 Unity 分析GPU ~~

Snapdragon簡介

由於GPU的詳細指標無法在Unity的Profiler上進行, 。在iOS上,您將使用Instruments來測量繪圖負載。

對於Android可以使用 Snapdragon Profiler - Qualcomm 您需要在Qualcomm上註冊才能下載。

它通過USB連接由Snapdragon處理器驅動的Android設備。Snapdragon Profiler允許開發人員分析CPU,GPU,DSP,內存,電源,散熱和網絡數據,以便他們找到並修復性能瓶頸。

特點和好處

  • 實時視圖可以輕鬆關聯時間軸上的系統資源使用情況
    • 分析CPU,GPU,DSP *,內存,電源,散熱和網絡數據指標
    • 從22個類別中的150多種不同硬件性能計數器中進行選擇
  • 跟蹤捕獲模式允許您在時間線上可視化內核和系統事件,以分析CPU,GPU和DSP上的低級系統事件。
    • 查看CPU調度和GPU階段數據,以查看應用程序花費時間的位置
  • Snapshot Capture ***模式允許您從任何OpenGL ES應用程序捕獲和調試渲染幀
    • 逐步並重放渲染幀繪製逐個調用調用
    • 查看和編輯着色器並在設備上預覽結果
    • 查看和調試像素歷史記錄
  • 捕獲並查看每個繪製調用的GPU指標

GPU API:OpenGL ES 3.1,OpenCL 2.1和Vulkan 1.0 **

*需要Snapdragon 820(或更高版本)處理器

**需要Android N(或帶有支持Vulkan的圖形驅動程序的Android 6.0設備)

***需要Snapdragon 805(或更高版本)處理器和Android 6.0(或更高版本)

https://youtu.be/9wxxTl_Su7U

 

 

RenderDoc非常好

https://docs.unity3d.com/2018.3/Documentation/Manual/RenderDocIntegration.html

捕獲非常簡單。

安裝RenderDoc後,在Unity的GameView上播放之前加載RenderDoc。

你所要做的就是捕捉按鈕Pochiru

在PixelHistory中,您可以看到屏幕上點數的填充歷史

您可以看到Mesh內容的值。

 

 

 

33、 與ETC1相比,ETC2在顏色部分得到改善的故事

https://enrike3.hatenablog.com/entry/2018/04/21/210901

我在 談到壓縮紋理, 源自DXT1的初始壓縮紋理的族譜將4x4 = 16px視爲一個塊,並且

每塊使用64位顏色(RGB),即64/16 = 4bpp(每像素位)。

在這種情況下,由於不存在α,因此每個塊也添加64位(4bpp)的alpha-

不透明圖像4 bpp-具有透明度8bpp的圖像是DXT2~5和ETC2的配置。

由於PVRTC也表示4bpp的alpha值,因此具有透明度的塊具有嚴重的顏色質量。

OPTPiX博客上有一篇很好的評論,關於

什麼算法在RGBpp8 (24bpp)的4bpp的嚴格約束下壓縮,即壓縮比爲1/6 。

ETC改進

ETC1的優點是它可以在亮度表中產生白色和黑色,因此

每個塊有三種或更多顏色具有不同傾向(不能用代表性顏色的混合表示)的堵塞問題,這是DXT1的弱點,如果是白色或黑色,即使顏色增加也應該是好的。塊感比DXT1軟,因爲存在子塊劃分。

在另一方面,在情況下,在博客OPTPiX不同色調ETC1的弱點是津市對角線,

這是壓縮紋理的一個薄弱點,因爲它甚至不通過劃分子塊在垂直順利,甚至通過將橫向色伸出的很這很明顯。

如果你看一下ETC1,我想你可以看到Unity左臂周圍的顏色突出和右臂的袖子也是。

簡單的DXT1並不是特別弱,但ETC1還不夠好。

 

ETC2正在堅定地研究ETC1的弱點。

增加了三種沒有子塊劃分的新模式,ETC1中弱的圖像得到了顯着改善。

詳細信息在以下文檔中詳述。這不僅僅是爲了獲得透明度。

ETC2: Texture Compression using Invalid Combinations https://www.semanticscholar.org/paper/ETC2%3A-texture-compression-using-invalid-Str%C3%B6m-Pettersson/3099e5c603c1c7c7ef735d3ebfe4c3032691fd30

與BC7和ASTC等每塊128位的新一代壓縮相比,質量似乎有點下降,但是到2018年它仍然可以廣泛使用並且質量非常好,因此ETC2可能不是一個好的格式我想。

 

 

 

34、在不使用UnityEngine.UI的情況下在Canvas上繪圖

看Unity UGUI的開源代碼,UnityEngine.UI.dll的內容在Bitbuckethttps://bitbucket.org/Unity-Technologies/ui中。每個人都可以閱讀它, 會看到是有Dirty髒標記(頂點,材質,Layout三個髒標記吧),Unity 會在 Canvas.willRenderCanvases事件中檢查髒標記,如果有就會重新繪製合批等等操作。

 

這個只是爲了更好的理解UGUI

UnityEngine.UI.dll是一個用C#編寫的託管dll。

另一方面,Canvas,CanvasGroup,CanvasRenderer等是本機組件,命名空間也屬UnityEngine。

Canvas沒有對UnityEngine.UI.dll的依賴,如果你想在Canvas上繪圖,只需使用CanvasRenderer即可。

using UnityEngine;
[RequireComponent(typeof(CanvasRenderer))]
public class RawImageTest : MonoBehaviour
{
    [SerializeField]
    private Texture2D _texture = null;
    public Texture2D Texture
    {
        get { return _texture; }
        set
        {
            if (_texture != value)
            {
                _renderRequired = true;
                _texture = value;
            }
        }
    }
    private CanvasRenderer _canvasRenderer = null;
    public CanvasRenderer CanvasRenderer
    {
        get { return _canvasRenderer != null ? _canvasRenderer : (_canvasRenderer = GetComponent<CanvasRenderer>()); }
    }
    void Start()
    {
        Canvas.willRenderCanvases += Canvas_willRenderCanvases;
    }
    private void OnDestroy()
    {
        Canvas.willRenderCanvases -= Canvas_willRenderCanvases;
    }
    private void Canvas_willRenderCanvases()
    {
        if (!_renderRequired)
            return;
        _renderRequired = false;
        const float size = 200;
        var mesh = new Mesh();
        mesh.vertices = new Vector3[]
        {
            new Vector3(-size, -size),
            new Vector3(-size,  size),
            new Vector3( size,  size),
            new Vector3( size, -size),
        };
        mesh.uv = new Vector2[]
        {
            new Vector2(0, 0),
            new Vector2(0, 1),
            new Vector2(1, 1),
            new Vector2(1, 0),
        };
        mesh.triangles = new int[] { 0, 1, 2, 2, 3, 0 };
        var renderer = this.CanvasRenderer;
        renderer.SetMesh(mesh);
        renderer.materialCount = 1; //請注意,如果您忘記了這一點,將無法繪製
        renderer.SetMaterial(Canvas.GetDefaultCanvasMaterial(), 0);
        renderer.SetTexture(this.Texture);
        renderer.SetColor(Color.white);
    }
    private bool _renderRequired = false;
#if UNITY_EDITOR
    private void OnValidate()
    {
        _renderRequired = true;
        if (!Application.isPlaying)
        {
            Canvas_willRenderCanvases();
        }
    }
#endif
}

此代碼的重要部分是繪圖時序,它使用Canvas.willRenderCanvases事件。這個事件是在LateUpdate之後觸發。

Canvas.willRenderCanvases + = Canvas_willRenderCanvases;

您需要做的就是在CanvasRenderer中填寫您需要在此事件中繪製的內容。

var renderer = this.CanvasRenderer;
renderer.SetMesh(mesh);
renderer.materialCount = 1; 
renderer.SetMaterial(Canvas.GetDefaultCanvasMaterial(), 0);
renderer.SetTexture(this.Texture);
renderer.SetColor(Color.white);

Canvas.willRenderCanvases 在每一幀調用。

Canvas與Unity的DynamicBatching 合批不同, 但是批處理條件類似,因此如果您知道相同的材質和參數匹配, 由於CanvasRenderer扮演類似於MaterialPropertyBlock的角色,因此以下方法可以與MaterialPropertyBlock相同的方式使用。但是,無法指定着色器參數名稱

  • CanvasRenderer.SetTexture ※_MainTex
  • CanvasRenderer.SetAlphaTexture ※_AlphaTex
  • CanvasRenderer.SetColor ※適用於_Color
  • CanvasRenderer.SetAlpha ※僅8適用於_Color 的Alpha

如果這些參數完全匹配,它將被正確批處理。

 

CanvasUpdateRegistry 和 ICanvasElement

我認爲UnityEngine.UI.CanvasUpdateRegistryhttps://docs.unity3d.com/ja/current/ScriptReference/UI.CanvasUpdateRegistry.html類在理解uGUI時非常重要。

剛剛提到 Canvas.willRenderCanvases事件分爲佈局和渲染兩部分。

uGUI具有VerticalLayoutGroup等佈局組件。

如果VerticalLayoutGroup 在繪圖組件將Mesh發送到CanvasRenderer後調整佈局,則1幀繪製變得奇怪。因此,必須始終在繪製之前完成佈局。有很多方法可以實現這一點,例如提供另一個佈局事件,保證在Canvas .willRenderCanvases事件之前觸發,但是uGUI 選擇將Canvas .willRenderCanvases切割成兩個。

  • 需要重新佈局的UGUI組件使用CanvasUpdateRegistry註冊自己,並使用CanvasUpdateRegistry.RegisterCanvasElementForLayoutRebuild
  • 需要重新繪製的UGUI組件使用CanvasUpdateRegistry註冊CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild
  • CanvasUpdateRegistry將佈局指令發送到Canvas.willRenderCanvases時刻爲佈局註冊的組件。 佈局完成後,將重繪指令發送到註冊爲重繪的組件
  • 在CanvasUpdateRegistry一側取消了佈局和重繪的註冊,因此它將在註冊的框架中執行一次。

ICanvasElement

可以使用CanvasUpdateRegistry註冊任何實現UnityEngine.UI.ICanvasElement接口的類。不是MonoBehaviour,可以在普通的C#類中使用。

(*但是,當使用普通類時,似乎大多數都採用MonoBehaviour的形式,以免被transform和IsDestroyed的實現所困擾)

uGUI的組件基於實現ICanvasElement 的基類UnityEngine.UI.Graphic類,並且佈局組件也隨時包含在UnityEngine.UI.LayoutRebuilder類中。

ICanvasElement實現中最重要的一點是ICanvasElement.Rebuild方法。這是佈局和重繪的主體。您可以通過查看參數傳遞的UnityEngine.UI.CanvasUpdate枚舉類型來查看是否爲佈局調用了當前的Rebuild 。如您所見,此枚舉有三個佈局成員和兩個繪圖成員。

應用一下

using UnityEngine;
using UnityEngine.UI;
[RequireComponent(typeof(CanvasRenderer))]
public class RawImageTest : MonoBehaviour, ICanvasElement
{
    [SerializeField]
    private Texture2D _texture = null;
    public Texture2D Texture
    {
        get { return _texture; }
        set
        {
            if (_texture != value)
            {
                _texture = value;
                SetDirty();
            }
        }
    }
    private CanvasRenderer _canvasRenderer = null;
    public CanvasRenderer CanvasRenderer
    {
        get { return _canvasRenderer != null ? _canvasRenderer : (_canvasRenderer = GetComponent<CanvasRenderer>()); }
    }
    void OnEnable()
    {
        SetDirty();
    }
    private void Start()
    {
        StartCoroutine(DelayRegister());
    }
    //有一個IsDestroyed返回true的時間,所以我推遲了一點並註冊了它。
    private System.Collections.IEnumerator DelayRegister()
    {
        yield return null;
        SetDirty();
    }
    private void SetDirty()
    {
        CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild(this);
        Debug.Log("SetDirty");
    }
    private void Canvas_willRenderCanvases()
    {
        const float size = 200;
        var mesh = new Mesh();
        mesh.vertices = new Vector3[]
        {
            new Vector3(-size, -size),
            new Vector3(-size,  size),
            new Vector3( size,  size),
            new Vector3( size, -size),
        };
        mesh.uv = new Vector2[]
        {
            new Vector2(0, 0),
            new Vector2(0, 1),
            new Vector2(1, 1),
            new Vector2(1, 0),
        };
        mesh.triangles = new int[] { 0, 1, 2, 2, 3, 0 };
        var renderer = this.CanvasRenderer;
        renderer.SetMesh(mesh);
        renderer.materialCount = 1; //請注意,如果您忘記了這一點,將無法繪製
        renderer.SetMaterial(Canvas.GetDefaultCanvasMaterial(), 0);
        renderer.SetTexture(this.Texture);
        renderer.SetColor(Color.white);
    }
    #region ICanvasElement
    void ICanvasElement.Rebuild(CanvasUpdate executing)
    {
        Debug.LogFormat("Rebuild {0}", executing);
        if (executing == CanvasUpdate.PreRender)
            Canvas_willRenderCanvases();
    }
    public void LayoutComplete() { }
    public void GraphicUpdateComplete() { }
    public bool IsDestroyed()
    {
        var result = this == null;
        Debug.LogFormat("IsDestroyed {0}", result);
        return result;
    }
    #endregion
#if UNITY_EDITOR
    private void OnValidate()
    {
        SetDirty();
        if (!Application.isPlaying)
        {
            Canvas_willRenderCanvases();
        }
    }
#endif
}

您不再需要直接訂閱Canvas .willRenderCanvases,因此不再需要使用_renderRequired標誌來保護每個幀的處理。

https://enrike3.hatenablog.com/entry/2018/03/10/160041

https://enrike3.hatenablog.com/entry/2018/03/10/190715

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章