コード例 #1
0
    // Doesn't do material export; for that see ExportMeshPayload
    private GlTF_Node ExportMeshPayload_NoMaterial(
        BaseMeshPayload mesh,
        [CanBeNull] GlTF_Node parent,
        Matrix4x4?localXf = null)
    {
        ObjectName   meshNameAndId = new ObjectName(mesh.legacyUniqueName);
        GeometryPool pool          = mesh.geometry;
        Matrix4x4    xf            = localXf ?? mesh.xform;
        // Create a Node and (usually) a Mesh, both named after meshNameAndId.
        // This is safe because the namespaces for Node and Mesh are distinct.
        // If we have already seen the GeometryPool, the Mesh will be reused.
        // In this (less common) case, the Node and Mesh will have different names.

        // We don't actually ever use the "VERTEXID" attribute, even in gltf1.
        // It's time to cut it away.
        // Also, in gltf2, it needs to be called _VERTEXID anyway since it's a custom attribute
        GlTF_VertexLayout gltfLayout = new GlTF_VertexLayout(G, pool.Layout);

        int numTris = pool.NumTriIndices / 3;

        if (numTris < 1)
        {
            return(null);
        }

        NumTris += numTris;

        GlTF_Mesh gltfMesh;

        // Share meshes for any repeated geometry pool.
        if (!m_meshCache.TryGetValue(pool, out gltfMesh))
        {
            gltfMesh      = new GlTF_Mesh(G);
            gltfMesh.name = GlTF_Mesh.GetNameFromObject(meshNameAndId);
            gltfMesh.PresentationNameOverride = mesh.geometryName;
            m_meshCache.Add(pool, gltfMesh);

            // Populate mesh data only once.
            AddMeshDependencies(meshNameAndId, mesh.exportableMaterial, gltfMesh, gltfLayout);
            gltfMesh.Populate(pool);
            G.meshes.Add(gltfMesh);
        }

        // The mesh may or may not be shared, but every mesh will have a distinct node to allow them
        // to have unique transforms.
        GlTF_Node node = GlTF_Node.GetOrCreate(G, meshNameAndId, xf, parent, out _);

        node.m_mesh = gltfMesh;
        node.PresentationNameOverride = mesh.nodeName;
        return(node);
    }
コード例 #2
0
    // Adds to gltfMesh the glTF dependencies (primitive, material, technique, program, shaders)
    // required by unityMesh, using matObjName for naming the various material-related glTF
    // components. This does not add any geometry from the mesh (that's done separately using
    // GlTF_Mesh.Populate()).
    //
    // This does not create the material either. It adds a reference to a material that
    // presumably will be created very soon (if it hasn't previously been created).
    private void AddMeshDependencies(
        ObjectName meshName, IExportableMaterial exportableMaterial, GlTF_Mesh gltfMesh,
        GlTF_VertexLayout gltfLayout)
    {
        GlTF_Primitive primitive = new GlTF_Primitive(
            new GlTF_Attributes(G, meshName, gltfLayout));

        GlTF_Accessor indexAccessor = G.CreateAccessor(
            GlTF_Accessor.GetNameFromObject(meshName, "indices_0"),
            GlTF_Accessor.Type.SCALAR, GlTF_Accessor.ComponentType.USHORT,
            isNonVertexAttributeAccessor: true);

        primitive.indices = indexAccessor;
        if (gltfMesh.primitives.Count > 0)
        {
            Debug.LogError("More than one primitive per mesh is unimplemented and unsupported");
        }
        gltfMesh.primitives.Add(primitive);

        // This needs to be a forward-reference (ie, by name) because G.materials[exportableMaterial]
        // may not have been created yet.
        primitive.materialName = GlTF_Material.GetNameFromObject(exportableMaterial);
    }
コード例 #3
0
    // Updates glTF technique tech by adding all relevant attributes.
    // Pass:
    //   mesh - (optional) the attributes of some mesh that uses this material, for sanity-checking.
    private void AddAllAttributes(
        GlTF_Technique tech, IExportableMaterial exportableMaterial, GlTF_Attributes mesh)
    {
        GlTF_VertexLayout layout = new GlTF_VertexLayout(G, exportableMaterial.VertexLayout);

        if (mesh != null)
        {
            GlTF_VertexLayout meshLayout = mesh.m_layout;
            if (layout != meshLayout)
            {
                if (meshLayout.GetTexcoordSize(2) > 0)
                {
                    // We funnel timestamps in through GeometryPool.texcoord2 and write them out as
                    // _TB_TIMESTAMP.  Thus, the Pool's layout has a texcoord2 but the material's layout does
                    // not. This is a mismatch between the mesh data and the material props, but:
                    // 1. Timestamp isn't intended to be funneled to the material, so it's correct that the
                    //    material layoutdoesn't have texcoord2
                    // 2. It's fine if material attrs are a subset of the mesh attrs
                    // 3. This only affects gltf1; only materials with techniques need to enum their attrs.
                    // Maybe this check should be layout.IsSubset(meshLayout).
                    /* ignore this mismatch */
                }
                else
                {
                    Debug.LogWarning($"Layout for {exportableMaterial.DurableName} doesn't match mesh's");
                }
            }
        }

        // Materials are things that are shared across multiple meshes.
        // Material creation shouldn't depend on data specific to a particular mesh.
        // But it does. It's a hack.
        // Rather than do something reasonable like this:
        //
        //   Create material's technique's attributes based on layout
        //   Create mesh and its accessors based on layout
        //
        // We do this:
        //
        //   Create mesh and its accessors based on layout
        //     Lazily create the material used by the mesh
        //       Create material's technique's attributes based on the accessors
        //       of the last mesh we created
        AddAttribute("position", layout.PositionInfo.techniqueType,
                     GlTF_Technique.Semantic.POSITION, tech);
        if (layout.NormalInfo != null)
        {
            AddAttribute("normal", layout.NormalInfo.Value.techniqueType,
                         GlTF_Technique.Semantic.NORMAL, tech);
        }
        if (layout.ColorInfo != null)
        {
            AddAttribute("color", layout.ColorInfo.Value.techniqueType,
                         GlTF_Technique.Semantic.COLOR, tech);
        }
        if (layout.TangentInfo != null)
        {
            AddAttribute("tangent", layout.TangentInfo.Value.techniqueType,
                         GlTF_Technique.Semantic.TANGENT, tech);
        }
        // TODO: remove; this accessor isn't used. Instead, shaders use texcoord1.w
        if (layout.PackVertexIdIntoTexcoord1W)
        {
            AddAttribute("vertexId", GlTF_Technique.Type.FLOAT /* hardcoded, but this is gong away */,
                         GlTF_Technique.Semantic.UNKNOWN, tech);
        }
        for (int i = 0; i < 4; ++i)
        {
            var texcoordInfo = layout.GetTexcoordInfo(i);
            if (texcoordInfo != null)
            {
                GlTF_Technique.Semantic semantic = GlTF_Technique.Semantic.TEXCOORD_0 + i;
                AddAttribute($"texcoord{i}", texcoordInfo.Value.techniqueType, semantic, tech);
            }
        }
    }
コード例 #4
0
    public GlTF_Attributes(
        GlTF_Globals G, ObjectName meshName, GlTF_VertexLayout layout)
    {
        // This prefix should be used with possibly-nonconforming gltf data:
        // - texcoords that are not 2-element or that don't contain texture coordinates
        // - made-up / mythical semantics like VERTEXID
        string nonconformingPrefix = (G.GltfCompatibilityMode) ? "_TB_UNITY_" : "";

        m_layout = layout;

        {
            AttributeInfo positionInfo = layout.PositionInfo;
            positionAccessor = G.CreateAccessor(
                GlTF_Accessor.GetNameFromObject(meshName, "position"),
                positionInfo.accessorType, positionInfo.accessorComponentType);
            m_accessors.Add("POSITION", positionAccessor);
        }

        { if (layout.NormalInfo is AttributeInfo normalInfo)
          {
              normalAccessor = G.CreateAccessor(
                  GlTF_Accessor.GetNameFromObject(meshName, "normal"),
                  normalInfo.accessorType, normalInfo.accessorComponentType);
              // Genius particles put things that don't look like normals into the normal attribute.
              bool   isNonconforming = (layout.m_tbLayout.normalSemantic == Semantic.Position);
              string prefix          = isNonconforming ? nonconformingPrefix : "";
              m_accessors.Add(prefix + "NORMAL", normalAccessor);
          }
        }

        { if (layout.ColorInfo is AttributeInfo cInfo)
          {
              colorAccessor = G.CreateAccessor(
                  GlTF_Accessor.GetNameFromObject(meshName, "color"),
                  cInfo.accessorType, cInfo.accessorComponentType,
                  normalized: true);
              m_accessors.Add(G.Gltf2 ? "COLOR_0" : "COLOR", colorAccessor);
          }
        }

        { if (layout.TangentInfo is AttributeInfo tangentInfo)
          {
              tangentAccessor = G.CreateAccessor(
                  GlTF_Accessor.GetNameFromObject(meshName, "tangent"),
                  tangentInfo.accessorType, tangentInfo.accessorComponentType);
              m_accessors.Add("TANGENT", tangentAccessor);
          }
        }

        if (layout.PackVertexIdIntoTexcoord1W)
        {
            // The vertexid hack modifies the gl layout to extend texcoord1 so the vertexid
            // can be stuffed into it
            Debug.Assert(layout.m_tbLayout.GetTexcoordInfo(1).size == 3);
            Debug.Assert(layout.GetTexcoordSize(1) == 4);
        }

        GlTF_Accessor MakeAccessorFor(int texcoord)
        {
            var txcInfo = layout.GetTexcoordInfo(texcoord);

            if (txcInfo == null)
            {
                return(null);
            }
            Semantic tbSemantic = layout.m_tbLayout.GetTexcoordInfo(texcoord).semantic;
            string   attrName   = $"{nonconformingPrefix}TEXCOORD_{texcoord}";

            // Timestamps are tunneled into us via a texcoord because there's not really a better way
            // due to GeometryPool limitations. But that's an internal implementation detail. I'd like
            // them to have a better attribute name in the gltf.
            if (tbSemantic == Semantic.Timestamp)
            {
                // For b/141876882; Poly doesn't like _TB_TIMESTAMP
                if (!G.Gltf2)
                {
                    return(null);
                }
                attrName = "_TB_TIMESTAMP";
            }
            var ret = G.CreateAccessor(
                GlTF_Accessor.GetNameFromObject(meshName, $"uv{texcoord}"),
                txcInfo.Value.accessorType, txcInfo.Value.accessorComponentType);

            m_accessors.Add(attrName, ret);
            return(ret);
        }

        texCoord0Accessor = MakeAccessorFor(0);
        texCoord1Accessor = MakeAccessorFor(1);
        texCoord2Accessor = MakeAccessorFor(2);
        texCoord3Accessor = MakeAccessorFor(3);

        if (G.GltfCompatibilityMode)
        {
            TiltBrush.GeometryPool.VertexLayout tbLayout = layout.m_tbLayout;
            switch (tbLayout.texcoord0.semantic)
            {
            case Semantic.Unspecified when tbLayout.texcoord0.size == 2:
            case Semantic.XyIsUv:
            case Semantic.XyIsUvZIsDistance: {
                GlTF_Accessor accessor = GlTF_Accessor.CloneWithDifferentType(
                    G, texCoord0Accessor, GlTF_Accessor.Type.VEC2);
                m_accessors.Add("TEXCOORD_0", accessor);
                break;
            }
            }
            // No need to check the other texcoords because TB only ever puts texture coordinates
            // in texcoord0
        }
    }