4 Custom Asset Indexing
Sebastien Phaneuf редактировал(а) эту страницу 2023-12-22 14:11:48 -05:00

In order to allow quick resolving of all sorts of asset queries (even queries based in SerializedProperties) the Search backend has its own Asset Indexer.

The settings of your project indexing are handled through the Index Manager.

Here is a quick summary of what each index options allows:

  • Types: Indexes the object types information.
  • Properties: Indexes all properties (SerializedProperty and MaterialProperty) of all objects (only top level objects in a Scene or Prefab). Allows you to use the Property filter to search an index.
  • Extended: Indexes all Scene objects for a Unity scene and all subassets for an FBX.
  • Dependencies: Indexes all dependencies of all Assets. Using this setting creates a much larger index. Allows you to use the ref: filter to search an index.

What is custom Indexing?

CustomObjectIndexer are user defined functions that are called during the Asset Indexation process (done by the external processes called AssetWorker). CustomObjectIndexer functions allows user to add properties to the index for some specific type of assets.

Why custom Indexing?

By default if the properties option is selected in your Index, we process all SerializedProperties and MaterialProperties and index those results so you can search those properties:

p: t:texture FilterMode=0

But as a user you might want to add more to the index. Here are some reasons why you would like to do that?

  • Generate properties from other properties: you could add properties to the index by computing them. Example: you could tag all of your textures that are power of 2.
  • You want to implement your own tag/label system.
  • you feel that property indexing is long (it can be on large project), that it takes too much space (also can be true) and that you don't not need ALL SerializedProperties to be indexed. You only want a selected few and you knwo which one. Write your own CustomObjectIndexer for the types you are interested.
  • You want to add properties for types that are not SerializedObject (like json) or you want to be able to search hidden properties (like shader tags).

Writing a CustomObjectIndexer

Here is the code from ShaderIndexing.cs, a new custom indexer I added to the SearchExtensions package:

using UnityEngine;
using UnityEditor.Search;

public static class ShaderIndexing
{
    const int version = 1;

    public static string[] kTagIds = new string [] 
    {
        "LIGHTMODE",
        "SHADOWCASTER",
        "SHADOWCOLLECTOR",

        "Vertex",
        "VertexLM",
        "VertexLMRGBM",
        "REQUIREOPTIONS",
        "FORCENOSHADOWCASTING",
        "IGNOREPROJECTOR",
        "SHADOWSUPPORT",
        "PASSFLAGS",
        "RenderType",
        "DisableBatching",
        "LodFading",
        "RenderPipeline",
        "Picking",
        "SceneSelectionPass",
    };

    [CustomObjectIndexer(typeof(Shader), version = version)]
    public static void IndexShaderTagProperties(CustomObjectIndexerTarget context, ObjectIndexer indexer)
    {
        if (!(context.target is Shader shader))
            return;

        foreach(var tagIdStr in kTagIds)
        {
            var tagId = new UnityEngine.Rendering.ShaderTagId(tagIdStr);
            var tagValue = shader.FindSubshaderTagValue(0, tagId);
            var tagPropertyName = $"sh_{tagIdStr.ToLower()}";
            if (!string.IsNullOrEmpty(tagValue.name))
                indexer.IndexProperty(context.documentIndex, tagPropertyName, tagValue.name, true);
        }

    }
}

Test runner

You define a CustomObjectIndexer with a type and a version. Your indexing function will get passed an ObjectIndexer that you can use to add properties or words to the index.

If you use IndexProperty, the value of the property will indexed to allow partial matching (see below).

A property can be searched with the following syntax:

  • <propertyname>=<exactpropertyvalue> (Ex: sh_rendertype=opaque)
  • <propertyname>:<partialpropertyvalue> (Ex: sh_rendertype:opaq or sh_rendertype:opaque)

See Search Query Operators for more details.

CustomObjectIndexer version

Changing the version of your CustomObjectIndexer should trigger indexing of all the assets of the specified type.

How to test and debug CustomObjecIndexer?

CustomObjectIndexer are evaluated in the AssetWorker process which is NOT the Unity Editor Main process. This make it more difficult to debug how indexing happens and if you are populating the index correctly. Attaching a debugger to your CustomObjectIndexer function is really difficult.

In order to improve on this workflow, I added to the Search Extension package a bunch of test utilities to allow you to debug this.

The file CustomIndexationTests contains a test function that you can extend with your own test case:

public static IEnumerable<CustomIndexationTestCase> GetCustomIndexationTestCases()
{
    var scriptInPackage = "Packages/com.unity.search.extensions/Indexing/ShaderIndexing.cs";
    yield return new CustomIndexationTestCase("t:script", scriptInPackage, true);
    yield return new CustomIndexationTestCase("t:script", new string[] { scriptInPackage }, new string[] { scriptInPackage });

    var shaderInPackage = "Assets/Materials/SurfaceShader.shader";
    yield return new CustomIndexationTestCase("t:shader sh_rendertype=opaque", shaderInPackage, true);

    // Add your custom indexer tests here:
}

These test case can contain multiples files to index as well as a query and expected results. Running this test in the Unity Test Runner.

Test runner

Test runner

Can I test this workflow in my own project?

If you do not want to include the SearchExtensions package in your project, you can add the 2 following scripts to your project to allow you to test CustomObjectIndexer.