Merge branch 'dev'
This commit is contained in:
Коммит
860bf9ce41
|
@ -0,0 +1,12 @@
|
|||
artifacts/**
|
||||
build/**
|
||||
.build_script/**
|
||||
node_modules/**
|
||||
.DS_Store
|
||||
.npmrc
|
||||
!Documentation~
|
||||
!.Documentation
|
||||
npm-debug.log
|
||||
build.sh.meta
|
||||
build.bat.meta
|
||||
.idea/
|
|
@ -0,0 +1,99 @@
|
|||
test_editors:
|
||||
- version: 2018.3
|
||||
- version: 2019.1
|
||||
- version: 2019.2
|
||||
test_platforms:
|
||||
- name: win
|
||||
type: Unity::VM
|
||||
image: package-ci/win10:stable
|
||||
flavor: m1.large
|
||||
- name: mac
|
||||
type: Unity::VM::osx
|
||||
image: buildfarm/mac:stable
|
||||
flavor: m1.mac
|
||||
---
|
||||
pack:
|
||||
name: Pack
|
||||
agent:
|
||||
type: Unity::VM
|
||||
image: package-ci/win10:stable
|
||||
flavor: m1.large
|
||||
commands:
|
||||
- npm install upm-ci-utils -g --registry https://api.bintray.com/npm/unity/unity-npm
|
||||
- upm-ci package pack --package-path com.unity.film-tv.toolbox
|
||||
artifacts:
|
||||
packages:
|
||||
paths:
|
||||
- "upm-ci~/packages/**/*"
|
||||
|
||||
{% for editor in test_editors %}
|
||||
{% for platform in test_platforms %}
|
||||
test_{{ platform.name }}_{{ editor.version }}:
|
||||
name : Test {{ editor.version }} on {{ platform.name }}
|
||||
agent:
|
||||
type: {{ platform.type }}
|
||||
image: {{ platform.image }}
|
||||
flavor: {{ platform.flavor}}
|
||||
commands:
|
||||
- npm install upm-ci-utils -g --registry https://api.bintray.com/npm/unity/unity-npm
|
||||
- upm-ci package test --unity-version {{ editor.version }} --package-path com.unity.film-tv.toolbox
|
||||
artifacts:
|
||||
logs.zip:
|
||||
paths:
|
||||
- "upm-ci~/test-results/**/*"
|
||||
dependencies:
|
||||
- .yamato/upm-ci.yml#pack
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
|
||||
test_trigger:
|
||||
name: Tests Trigger
|
||||
agent:
|
||||
type: Unity::VM
|
||||
image: package-ci/win10:stable
|
||||
flavor: m1.large
|
||||
commands:
|
||||
- dir
|
||||
triggers:
|
||||
branches:
|
||||
only:
|
||||
- "/.*/"
|
||||
artifacts:
|
||||
logs:
|
||||
paths:
|
||||
- "upm-ci~/test-results/**/*"
|
||||
packages:
|
||||
paths:
|
||||
- "upm-ci~/packages/**/*"
|
||||
dependencies:
|
||||
- .yamato/upm-ci.yml#pack
|
||||
{% for editor in test_editors %}
|
||||
{% for platform in test_platforms %}
|
||||
- .yamato/upm-ci.yml#test_{{platform.name}}_{{editor.version}}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
|
||||
publish:
|
||||
name: Publish
|
||||
agent:
|
||||
type: Unity::VM
|
||||
image: package-ci/win10:stable
|
||||
flavor: m1.large
|
||||
commands:
|
||||
- npm install upm-ci-utils -g --registry https://api.bintray.com/npm/unity/unity-npm
|
||||
- upm-ci package publish --package-path com.unity.film-tv.toolbox
|
||||
triggers:
|
||||
tags:
|
||||
only:
|
||||
- /^(v|V)\d+\.\d+\.\d+(-preview(\.\d+)?)?$/
|
||||
artifacts:
|
||||
artifacts.zip:
|
||||
paths:
|
||||
- "upm-ci~/packages/*.tgz"
|
||||
dependencies:
|
||||
- .yamato/upm-ci.yml#pack
|
||||
{% for editor in test_editors %}
|
||||
{% for platform in test_platforms %}
|
||||
- .yamato/upm-ci.yml#test_{{ platform.name }}_{{ editor.version }}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
|
@ -0,0 +1,30 @@
|
|||
Shotgun CSV Import Export
|
||||
--------------------------
|
||||
|
||||
This sample shows how to create a timeline in Unity using a shot sequence from a Shotgun CSV export and export back modifications.
|
||||
|
||||
**This package is ONLY needed if you are running Unity versions prior to 2019.1.**
|
||||
If not, directly install `com.unity.film-tv.toolbox` via Package Manager window.
|
||||
|
||||
### How to install
|
||||
|
||||
* Download `ShotgunCSVImportExport.unitypackage` and import it in Unity
|
||||
* This will import in your Assets folder :
|
||||
* CSVImportExport.cs : a sample script demonstrating how to simply import / export a Shotgun CSV file
|
||||
* shot.csv : a shotgun csv export sample, used in the import.
|
||||
|
||||
### How to test
|
||||
|
||||
* Go to `Window > Film-TV toolbox > Samples > Shotgun` and select `Import CSV`
|
||||
* This creates a Timeline Asset (see shotgun_imported_timeline in the sample folder) from the `shot.csv` sample file :
|
||||
![Package Manager UI](../com.unity.film-tv.toolbox/Documentation~/images/ShotgunCSVImportResultTimeline.png)
|
||||
|
||||
* Make edits to the Timeline asset
|
||||
|
||||
* Go to `Window > Film-TV toolbox > Samples > Shotgun` and select `Export CSV`:
|
||||
* See export_from_unity.csv in the sample folder
|
||||
|
||||
### Limitations
|
||||
|
||||
* Having commas in fields (e.g.: `Opening sequence, part 2`) will confuse the parser
|
||||
* Having duplicate column names will cause errors due to duplicate keys
|
Двоичный файл не отображается.
|
@ -0,0 +1,6 @@
|
|||
|
||||
upm-ci~/**
|
||||
.Editor/**
|
||||
.yamato/**
|
||||
*.zip*
|
||||
TestRunnerOptions.json
|
|
@ -0,0 +1,9 @@
|
|||
# Changelog
|
||||
All notable changes to this package will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.1.0-preview.0] - 2019-04-15
|
||||
* Initialisation of the package
|
||||
* Material Remapper
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 67b3fe034077744fabda8e32148aab07
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,15 @@
|
|||
# Contributing
|
||||
|
||||
## If you are interested in contributing, here are some ground rules:
|
||||
* First share your plan with us before starting to avoid redundant or disruptive work
|
||||
* External contributors can use Github issues for that
|
||||
* Branch of master for hot fixes, or dev for other works
|
||||
* Please include the ticket ID in your commits (either Jira or Github issue)
|
||||
|
||||
|
||||
## All contributions are subject to the [Unity Contribution Agreement(UCA)](https://unity3d.com/legal/licenses/Unity_Contribution_Agreement)
|
||||
By making a pull request, you are confirming agreement to the terms and conditions of the UCA, including that your Contributions are your original creation and that you have complete right and authority to make your Contributions.
|
||||
|
||||
## Once you have a change ready following these ground rules.
|
||||
* Before submitting anything, please clean your history (squash, fix-up commits)
|
||||
* Then create a pull request targeting dev branch and add the issue ID either in the title or the description of the PR.
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 929c9cd4e3e8d475991b36dbf02edd61
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,62 @@
|
|||
Unity Film / TV toolbox
|
||||
=========================
|
||||
|
||||
This repository is a collection of experimental, proof of concept or helper tools for Film / TV productions.
|
||||
|
||||
Tools
|
||||
=========================
|
||||
|
||||
Material Remapper
|
||||
----------------------
|
||||
Material Remapper allows to more easily assign material to models containing a lot of meshes (Alembic, etc).
|
||||
It works with Legacy as well as SRP pipelines.
|
||||
|
||||
The tool was coded in large part by Mike Wutherick.
|
||||
|
||||
### How to Use
|
||||
|
||||
* Open the Material Remapper Window via `Window->Film-TV toolbox->Material Remapper`
|
||||
* Select the root GameObject containing the MeshRenderers you want to set-up
|
||||
* Click on "Update Scene Selection". This will load the list of unique MeshRenderers: ![import settings](images/WindowPopulated.png)
|
||||
* Add more materials to the session library by clicking "Add new Material Entry". Each new entry is initialized to the default current pipeline material.
|
||||
* Replace the default materials with the wanted materials.
|
||||
* Chose material assignments from the popup (Multiple materials per MeshRenderer are supported).
|
||||
* Once all assignments are configured, commit the changes to the Scene pressing "Apply Material Changes".
|
||||
* If at any moment you wish to return to the default state of the Material Remapper, press ResetRemapper.
|
||||
|
||||
Samples
|
||||
==========================
|
||||
|
||||
Since 2019.1, samples can be imported via the Package Manager window (Window > Package Manager) :
|
||||
![Package Manager UI](images/SamplesImport.png)
|
||||
|
||||
If you are using a previous version, download the sample on [film-tv-toolbox repository](https://github.com/Unity-Technologies/film-tv-toolbox).
|
||||
|
||||
|
||||
Shotgun CSV Import Export
|
||||
--------------------------
|
||||
|
||||
This sample shows how to create a timeline in Unity using a shot sequence from a Shotgun CSV export and export back modifications.
|
||||
|
||||
### How to install
|
||||
|
||||
* Import the sample via Package Manager UI
|
||||
* This will import in your Assets folder :
|
||||
* CSVImportExport.cs : a sample script demonstrating how to simply import / export a Shotgun CSV file
|
||||
* shot.csv : a shotgun csv export sample, used in the import.
|
||||
|
||||
### How to test
|
||||
|
||||
* Go to `Window > Film-TV toolbox > Samples > Shotgun` and select `Import CSV`
|
||||
* This creates a Timeline Asset (see shotgun_imported_timeline in the sample folder) from the `shot.csv` sample file :
|
||||
![Package Manager UI](images/ShotgunCSVImportResultTimeline.png)
|
||||
|
||||
* Make edits to the Timeline asset
|
||||
|
||||
* Go to `Window > Film-TV toolbox > Samples > Shotgun` and select `Export CSV`:
|
||||
* See export_from_unity.csv in the sample folder
|
||||
|
||||
### Limitations
|
||||
|
||||
* Having commas in fields (e.g.: `Opening sequence, part 2`) will confuse the parser
|
||||
* Having duplicate column names will cause errors due to duplicate keys
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 93 KiB |
Двоичные данные
com.unity.film-tv.toolbox/Documentation~/images/ShotgunCSVImportResultTimeline.png
Normal file
Двоичные данные
com.unity.film-tv.toolbox/Documentation~/images/ShotgunCSVImportResultTimeline.png
Normal file
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 81 KiB |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 131 KiB |
|
@ -0,0 +1,91 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 216ce80e76a3f4a848c2de909f9e6211
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 9
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: -1
|
||||
aniso: -1
|
||||
mipBias: -100
|
||||
wrapU: -1
|
||||
wrapV: -1
|
||||
wrapW: -1
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 92d0e0de0c145404ca3404dc94023ca9
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 94efd31d9b4904dc7a31e2065c0891db
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,194 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace UnityEditor.FilmTV.Toolbox
|
||||
{
|
||||
[Serializable]
|
||||
public class MaterialRemapperModel : ScriptableObject
|
||||
{
|
||||
[SerializeField]
|
||||
public List<Material> materialList = new List<Material>();
|
||||
[SerializeField]
|
||||
public List<Transform> objectsToRemap = new List<Transform>();
|
||||
[SerializeField]
|
||||
List<MeshRenderer> meshToRemap = new List<MeshRenderer>();
|
||||
[SerializeField]
|
||||
public List<RemapList> remapList = new List<RemapList>(); // the remapper - stores mesh, material and selected index (popup index for the remapper)
|
||||
|
||||
/// <summary>
|
||||
/// from our scene selection, prep the remapper, finding all of the mesh & materials that we'll want to remap
|
||||
/// </summary>
|
||||
/// <param name="objectList"></param>
|
||||
public void FindMeshesAndMaterials(List<Transform> objectList)
|
||||
{
|
||||
objectsToRemap.Clear();
|
||||
meshToRemap.Clear();
|
||||
objectsToRemap = objectList;
|
||||
foreach (var entry in objectList)
|
||||
{
|
||||
var meshList = entry.GetComponentsInChildren<MeshRenderer>();
|
||||
meshToRemap.AddRange(meshList.ToList());
|
||||
}
|
||||
|
||||
var uniqueMeshList = new List<MeshRenderer>();
|
||||
remapList.Clear();
|
||||
|
||||
materialList = meshToRemap.SelectMany(m => m.sharedMaterials).Distinct().ToList();
|
||||
|
||||
// build our list of unique meshes
|
||||
foreach (var mesh in meshToRemap)
|
||||
{
|
||||
// if we don't already have the name in our list, then add it
|
||||
if (!uniqueMeshList.Contains(mesh))
|
||||
{
|
||||
var newRemap = new RemapList()
|
||||
{
|
||||
mesh = mesh,
|
||||
selectedIndex = new List<int>()
|
||||
};
|
||||
// prep our remapper
|
||||
newRemap.selectedIndex.Clear();
|
||||
foreach (var mat in mesh.sharedMaterials)
|
||||
{
|
||||
var idx = materialList.IndexOf(mat);
|
||||
newRemap.selectedIndex.Add(idx);
|
||||
}
|
||||
|
||||
// build the list of things that we are going to remap
|
||||
remapList.Add(newRemap);
|
||||
uniqueMeshList.Add(mesh);
|
||||
}
|
||||
}
|
||||
Debug.Log("MaterialRemapper:FindMeshesAndMaterials() - object count: " + objectList.Count + " Found : " + meshToRemap.Count + " meshes, " + uniqueMeshList.Count + " unique meshes");
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// reset everything
|
||||
/// </summary>
|
||||
public void ResetData()
|
||||
{
|
||||
materialList.Clear();
|
||||
objectsToRemap.Clear();
|
||||
meshToRemap.Clear();
|
||||
remapList.Clear();
|
||||
}
|
||||
|
||||
|
||||
public static Material GetDefaultMaterial()
|
||||
{
|
||||
Material defaultMat;
|
||||
var pipelineAsset = GraphicsSettings.renderPipelineAsset;
|
||||
if( pipelineAsset != null)
|
||||
{
|
||||
#if UNITY_2019_1_OR_NEWER
|
||||
defaultMat = pipelineAsset.defaultMaterial;
|
||||
#else
|
||||
defaultMat = pipelineAsset.GetDefaultMaterial();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
defaultMat = new Material(Shader.Find("Standard"));
|
||||
}
|
||||
return defaultMat;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Do the remapping!
|
||||
/// </summary>
|
||||
public void ApplyMaterialChanges()
|
||||
{
|
||||
Debug.Log("MaterialRemapper:ApplyMaterialChanges() - " + meshToRemap.Count + " total meshes - " + remapList.Count + " unique meshes to remap to " + materialList.Count + " materials");
|
||||
// iterate through all of the meshes
|
||||
foreach (var mesh in meshToRemap)
|
||||
{
|
||||
var sourceMesh = mesh;
|
||||
|
||||
// for each mesh, find the remap equiv
|
||||
var remap = remapList.FirstOrDefault(u => u.mesh.name == mesh.name);
|
||||
|
||||
Debug.Log("mesh: " + sourceMesh.name + " found remap mesh: " + remap.mesh.name);
|
||||
|
||||
// build our materials struct
|
||||
Debug.Log("preparing to remap materials for mesh: " + sourceMesh.name);
|
||||
var matList = new List<Material>();
|
||||
foreach( var matIdx in remap.selectedIndex)
|
||||
{
|
||||
if( matIdx != -1)
|
||||
{
|
||||
var newMat = materialList[matIdx];
|
||||
matList.Add(newMat);
|
||||
Debug.Log(" - material: " + newMat.name);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Log(" - no material");
|
||||
}
|
||||
}
|
||||
|
||||
if( matList.Count > 0)
|
||||
{
|
||||
Undo.RegisterCompleteObjectUndo(sourceMesh.sharedMaterials.Cast<UnityEngine.Object>().ToArray(), "Assign Materials");
|
||||
Debug.Log("Applying materials...");
|
||||
sourceMesh.sharedMaterials = matList.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// the remapping list of mesh to materials
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class RemapList
|
||||
{
|
||||
public MeshRenderer mesh;
|
||||
public List<int> selectedIndex = new List<int>();
|
||||
}
|
||||
|
||||
/********************************
|
||||
* utility functions
|
||||
********************************/
|
||||
|
||||
/// <summary>
|
||||
/// get count of mesh in our selection
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public int GetMeshCount()
|
||||
{
|
||||
var meshCount = 0;
|
||||
foreach (var entry in objectsToRemap)
|
||||
{
|
||||
var count = entry.GetComponentsInChildren<MeshRenderer>().Length;
|
||||
meshCount += count;
|
||||
}
|
||||
return meshCount;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// figure out the count of unique mesh in our list
|
||||
/// </summary>
|
||||
public List<MeshRenderer> GetUniqueMeshList()
|
||||
{
|
||||
var ret = new List<MeshRenderer>();
|
||||
|
||||
foreach (var entry in objectsToRemap)
|
||||
{
|
||||
var meshList = entry.GetComponentsInChildren<MeshRenderer>();
|
||||
foreach (var mesh in meshList)
|
||||
{
|
||||
if (!ret.FirstOrDefault(u => u.name == mesh.name))
|
||||
{
|
||||
ret.Add(mesh);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6b4a85f04314e43debe43eae1ff22535
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,246 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace UnityEditor.FilmTV.Toolbox
|
||||
{
|
||||
[Serializable]
|
||||
public class MaterialRemapperView : EditorWindow
|
||||
{
|
||||
[SerializeField]
|
||||
Transform[] selection; // user scene selection
|
||||
|
||||
// UI States
|
||||
bool showGlobalUI;
|
||||
bool showMeshRemapList;
|
||||
[SerializeField]
|
||||
MaterialRemapperModel model;
|
||||
|
||||
static MaterialRemapperView instance;
|
||||
Vector2 scrollPos;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// initialization
|
||||
/// </summary>
|
||||
[MenuItem(MaterialRemapperLocalization.menuItemLabel)]
|
||||
public static void ShowWindow()
|
||||
{
|
||||
var thisWindow = GetWindow<MaterialRemapperView>(false, MaterialRemapperLocalization.windowLabel, true);
|
||||
thisWindow.ResetData();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// reset ourself
|
||||
/// </summary>
|
||||
void ResetData()
|
||||
{
|
||||
model.ResetData();
|
||||
}
|
||||
|
||||
|
||||
void ResetSceneSelection()
|
||||
{
|
||||
model.ResetData();
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
instance = this;
|
||||
if (model == null)
|
||||
instance.model = CreateInstance<MaterialRemapperModel>();
|
||||
|
||||
instance.selection = Selection.GetTransforms(
|
||||
SelectionMode.TopLevel | SelectionMode.OnlyUserModifiable);
|
||||
|
||||
Undo.RegisterCompleteObjectUndo(instance.selection, "Replace Materials in Selection");
|
||||
|
||||
instance.model.objectsToRemap = instance.selection.ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draw the UI
|
||||
/// </summary>
|
||||
void OnGUI()
|
||||
{
|
||||
var currentHeight = position.height;
|
||||
scrollPos = EditorGUILayout.BeginScrollView(scrollPos, GUILayout.Width(EditorGUIUtility.currentViewWidth), GUILayout.Height(currentHeight));
|
||||
{
|
||||
GUILayout.Space(20);
|
||||
EditorGUILayout.BeginVertical();
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
{
|
||||
if (GUILayout.Button(MaterialRemapperLocalization.updateSceneSelection, GUILayout.Width(300), GUILayout.Height(35)))
|
||||
{
|
||||
selection = Selection.GetTransforms(SelectionMode.TopLevel | SelectionMode.OnlyUserModifiable);
|
||||
Debug.Log("Selection updated, found : " + selection.Length + " entries");
|
||||
// reset the scene selection (doesn't reset the material list)
|
||||
ResetSceneSelection();
|
||||
model.FindMeshesAndMaterials(selection.ToList()); // build a list of MeshRenderers from our selection
|
||||
}
|
||||
if (GUILayout.Button(MaterialRemapperLocalization.resetRemapper, GUILayout.Width(300), GUILayout.Height(35)))
|
||||
{
|
||||
// reset everything
|
||||
ResetData();
|
||||
}
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
showGlobalUI = model.objectsToRemap.Count > 0;
|
||||
GUILayout.Space(20);
|
||||
GUILayout.Label(MaterialRemapperLocalization.meshSelectLabel, EditorStyles.boldLabel, GUILayout.Width(500));
|
||||
|
||||
// hide the UI unless we have a selection
|
||||
if (showGlobalUI)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
{
|
||||
// list of objects that we want to remap
|
||||
EditorGUILayout.BeginVertical(GUILayout.Width(250));
|
||||
{
|
||||
GUILayout.Space(10);
|
||||
// list of objects
|
||||
GUILayout.Label(MaterialRemapperLocalization.objectsToRemap, EditorStyles.boldLabel,
|
||||
GUILayout.MinWidth(400));
|
||||
// list the objects
|
||||
foreach (var entry in model.objectsToRemap)
|
||||
{
|
||||
EditorGUILayout.ObjectField(entry.name, entry, typeof(Object), true,
|
||||
GUILayout.MinWidth(400));
|
||||
}
|
||||
|
||||
// temp debug values
|
||||
GUILayout.Label(MaterialRemapperLocalization.selectionDetails, EditorStyles.boldLabel,
|
||||
GUILayout.Width(250));
|
||||
var meshCount = model.GetMeshCount();
|
||||
GUILayout.Label(MaterialRemapperLocalization.meshCountInSelection + meshCount,
|
||||
GUILayout.Width(250));
|
||||
var uniqueMesh = model.GetUniqueMeshList().Count;
|
||||
GUILayout.Label(MaterialRemapperLocalization.uniqueMeshCount + uniqueMesh,
|
||||
GUILayout.Width(250));
|
||||
}
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
{
|
||||
// list of materials that we want to use for remapping
|
||||
EditorGUILayout.BeginVertical(GUILayout.Width(250));
|
||||
{
|
||||
// list of materials
|
||||
GUILayout.Label(MaterialRemapperLocalization.materialsLibrary, EditorStyles.boldLabel,
|
||||
GUILayout.MinWidth(400));
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
{
|
||||
if (GUILayout.Button(MaterialRemapperLocalization.addNewMaterialEntry,
|
||||
GUILayout.Width(400), GUILayout.Height(35)))
|
||||
{
|
||||
var newMat = MaterialRemapperModel.GetDefaultMaterial();
|
||||
// add to our temp list of materials
|
||||
model.materialList.Add(newMat);
|
||||
newMat.name = "MaterialRemap";
|
||||
}
|
||||
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
for (var i = 0; i < model.materialList.Count; i++)
|
||||
{
|
||||
model.materialList[i] = (Material) EditorGUILayout.ObjectField(model.materialList[i].name,
|
||||
model.materialList[i], typeof(Material), true, GUILayout.MinWidth(400));
|
||||
}
|
||||
|
||||
}
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
{
|
||||
GUILayout.Space(20);
|
||||
|
||||
|
||||
// if we have any, show the remapper
|
||||
showMeshRemapList = model.materialList.Count > 0;
|
||||
|
||||
if (showMeshRemapList)
|
||||
{
|
||||
GUILayout.Label(MaterialRemapperLocalization.meshRemapLabel, EditorStyles.boldLabel, GUILayout.Width(500));
|
||||
|
||||
// remapping UI
|
||||
EditorGUILayout.BeginHorizontal(GUILayout.Width(500));
|
||||
{
|
||||
// mesh list to map to materials
|
||||
EditorGUILayout.BeginVertical();
|
||||
{
|
||||
GUILayout.Label(MaterialRemapperLocalization.remapMesh, EditorStyles.boldLabel, GUILayout.Width(500));
|
||||
|
||||
// list the objects
|
||||
foreach (var remapItem in model.remapList)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
// mesh that we want to remap
|
||||
GUILayout.Label(remapItem.mesh.name, GUILayout.Width(200));
|
||||
|
||||
// show all of the materials in the mesh
|
||||
for (var j = 0; j < remapItem.mesh.sharedMaterials.Length; j++)
|
||||
{
|
||||
// do we have any materials to remap
|
||||
remapItem.selectedIndex[j] = EditorGUILayout.Popup(remapItem.selectedIndex[j], model.materialList.Select(x=>x.name).ToArray(), GUILayout.Width(200));
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
}
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
else
|
||||
{
|
||||
GUILayout.Label(MaterialRemapperLocalization.noMaterialToRemap, EditorStyles.boldLabel, GUILayout.Width(500));
|
||||
}
|
||||
}
|
||||
if (showGlobalUI)
|
||||
{
|
||||
GUILayout.FlexibleSpace();
|
||||
if (GUILayout.Button("Apply Material Changes", GUILayout.Width(300), GUILayout.Height(35)))
|
||||
{
|
||||
model.ApplyMaterialChanges();
|
||||
}
|
||||
}
|
||||
GUILayout.Space(20);
|
||||
}
|
||||
}
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
EditorGUILayout.EndScrollView();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Localization table for the MaterialRemapperView class
|
||||
/// </summary>
|
||||
static class MaterialRemapperLocalization
|
||||
{
|
||||
// UI Labels
|
||||
public const string menuItemLabel = "Window/Film-TV toolbox/Material Remapper";
|
||||
public const string windowLabel = "Material Remapper";
|
||||
public const string meshSelectLabel = "Select Scene objects to remap";
|
||||
public const string meshRemapLabel = "Remap materials to object meshes";
|
||||
public const string updateSceneSelection = "Update Scene Selection";
|
||||
public const string resetRemapper = "Reset Remapper";
|
||||
public const string objectsToRemap = "Objects to Remap";
|
||||
public const string selectionDetails = "Selection Details:";
|
||||
public const string meshCountInSelection = " Mesh Count in selection: ";
|
||||
public const string uniqueMeshCount = " Unique Mesh Count: ";
|
||||
public const string materialsLibrary = "Materials Library";
|
||||
public const string addNewMaterialEntry = "Add new Material Entry";
|
||||
public const string remapMesh = "Mesh to Remap";
|
||||
public const string noMaterialToRemap = "Add some materials to remap";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 79d012f0d5645e547b2f0d88513f2145
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"name": "Unity.Film-TV.Toolbox.Editor",
|
||||
"references": [],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": []
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 30d31d6520f4144ea9d168c2c6468e0a
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f035652d61b6f48d88f1fea020a72b2c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,48 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.FilmTV.Toolbox
|
||||
{
|
||||
public static class PackageUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// Utils function to get the relative path of a file considering a base folder
|
||||
/// </summary>
|
||||
public static string GetRelativeFolderPath(string baseFolderPath, string filePath = "")
|
||||
{
|
||||
const string universalSeparator = @"/";
|
||||
const string windowsSeparator = @"\";
|
||||
|
||||
// Conforming paths to ease next steps
|
||||
filePath = filePath.Replace(windowsSeparator, universalSeparator);
|
||||
baseFolderPath = baseFolderPath.Replace(windowsSeparator, universalSeparator);
|
||||
|
||||
// baseFolderPath must end with a slash to indicate folder
|
||||
baseFolderPath = baseFolderPath.TrimEnd();
|
||||
if (!baseFolderPath.EndsWith(universalSeparator))
|
||||
{
|
||||
baseFolderPath += universalSeparator;
|
||||
}
|
||||
|
||||
// Using URIs to find the relative path
|
||||
var sampleFolderAbsoluteURI = new Uri(Path.GetDirectoryName(filePath));
|
||||
var projectFolderAbsoluteURI = new Uri(baseFolderPath);
|
||||
var sampleFolderRelativePath =
|
||||
Uri.UnescapeDataString(
|
||||
projectFolderAbsoluteURI.MakeRelativeUri(sampleFolderAbsoluteURI).ToString()
|
||||
.Replace('/', Path.DirectorySeparatorChar)
|
||||
);
|
||||
return sampleFolderRelativePath;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Utils function to get the relative path of the current caller with current Unity directory as a base folder
|
||||
/// </summary>
|
||||
public static string GetCallerRelativeToProjectFolderPath([CallerFilePath] string filePath = "")
|
||||
{
|
||||
return GetRelativeFolderPath(Directory.GetCurrentDirectory(), filePath);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2085f19c60b074b2582a726e6d01f52e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,5 @@
|
|||
film-tv-toolbox copyright © 2018-2019 Unity Technologies ApS
|
||||
|
||||
Licensed under the Unity Companion License for Unity-dependent projects--see [Unity Companion License](http://www.unity3d.com/legal/licenses/Unity_Companion_License).
|
||||
|
||||
Unless expressly provided otherwise, the Software under this license is made available strictly on an “AS IS” BASIS WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. Please review the license for details on these and other terms and conditions.
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3faaf5cb4781e440ebd864b86032a91d
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,25 @@
|
|||
Unity Film / TV toolbox
|
||||
=========================
|
||||
|
||||
This repository is a collection of experimental, proof of concept or helper tools for Film / TV productions.
|
||||
|
||||
Prerequistes
|
||||
---------------
|
||||
* This has been tested for `>= 2018.3`
|
||||
* Windows / OSX, not tested on Linux
|
||||
|
||||
Content
|
||||
----------------
|
||||
|
||||
### Tools
|
||||
|
||||
* Material Remapper : allows to more easily assign material to models containing a lot of meshes
|
||||
|
||||
### Samples
|
||||
|
||||
* Simple Shotgun CSV Import / Export : This shows how to create a timeline in Unity using a shot sequence from a Shotgun CSV export and export back modifications.
|
||||
|
||||
Required dependencies
|
||||
---------------
|
||||
|
||||
No dependencies are required.
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 96baefe566d2d47938274840ec9c8f1e
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2f49bff734c204932a31359c8f8d0849
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b040897da15654d3e8621fe1dc146b3c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"displayName" : "ShotgunCSVImportExport",
|
||||
"description" : "This shows how to create a timeline in Unity using a shot sequence from a Shotgun CSV export and export back modifications."
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Timeline;
|
||||
using UnityEditor;
|
||||
using UnityEditor.FilmTV.Toolbox;
|
||||
|
||||
public static class CsvImportExport
|
||||
{
|
||||
const int k_FPS = 24;
|
||||
const string k_ImportFileName = "shot.csv";
|
||||
const string k_ExportFileName = "export_from_unity.csv";
|
||||
const string k_TimelineAssetName = "shotgun_imported_timeline.asset";
|
||||
static string s_PathToFile = PackageUtils.GetCallerRelativeToProjectFolderPath();
|
||||
const string k_TimelineObjectName = "Sample Shotgun CSV timeline";
|
||||
|
||||
[MenuItem("Window/Film-TV toolbox/Samples/Shotgun/Import CSV")]
|
||||
public static void ImportCsv ()
|
||||
{
|
||||
var timeline = ScriptableObject.CreateInstance("TimelineAsset") as TimelineAsset;
|
||||
timeline.name = k_TimelineObjectName;
|
||||
timeline.editorSettings.fps = k_FPS;
|
||||
var track = timeline.CreateTrack<ControlTrack>(null, "");
|
||||
|
||||
foreach (var row in ReadCsvFile(Path.Combine(s_PathToFile, k_ImportFileName)))
|
||||
{
|
||||
var clip = track.CreateClip<ControlPlayableAsset>();
|
||||
var clipAsset = clip.asset as ControlPlayableAsset;
|
||||
|
||||
clipAsset.name = row["Shot Code"];
|
||||
clip.displayName = row["Shot Code"];
|
||||
clip.start = (Convert.ToDouble(row["Cut In"]) / k_FPS);
|
||||
// In Unity, the last frame is exclusive. frames goes : [start; end[
|
||||
clip.duration = (Convert.ToDouble(row["Cut Out"]) - Convert.ToDouble(row["Cut In"]) + 1 ) / k_FPS;
|
||||
}
|
||||
|
||||
Debug.Log($"Loaded {k_ImportFileName} from {s_PathToFile}.");
|
||||
AssetDatabase.CreateAsset(timeline, Path.Combine(s_PathToFile, k_TimelineAssetName ));
|
||||
Debug.Log($"Created Timeline Asset in {s_PathToFile}.");
|
||||
}
|
||||
|
||||
[MenuItem("Window/Film-TV toolbox/Samples/Shotgun/Export CSV")]
|
||||
public static void ExportCsv()
|
||||
{
|
||||
// Get the actual timeline object
|
||||
var timelineAsset = AssetDatabase.LoadAssetAtPath<TimelineAsset>(Path.Combine(s_PathToFile, k_TimelineAssetName));
|
||||
|
||||
// Each dictionary in the list represents a row in the CSV file
|
||||
// Each value in the row is addressable by its column name
|
||||
var toWrite = new List<Dictionary<string, string>>();
|
||||
|
||||
var track = timelineAsset.GetOutputTrack(0);
|
||||
foreach (var clip in track.GetClips())
|
||||
{
|
||||
var start = Convert.ToInt64(clip.start * k_FPS);
|
||||
// In Shotgun, the last frame is inclusive. frames goes : [start; end]
|
||||
// remove the "padding" we added
|
||||
var end = Convert.ToInt64((clip.duration + clip.start) * k_FPS) - 1;
|
||||
|
||||
var clipAsset = clip.asset as ControlPlayableAsset;
|
||||
var shotCode = clipAsset.name;
|
||||
|
||||
var dict = new Dictionary<string, string>
|
||||
{
|
||||
{"Shot Code", shotCode },
|
||||
{"Cut In", start.ToString() },
|
||||
{"Cut Out", end.ToString() }
|
||||
};
|
||||
toWrite.Add(dict);
|
||||
}
|
||||
|
||||
var pathToOutputFile = Path.Combine(s_PathToFile, k_ExportFileName);
|
||||
Debug.Log($"Exported clip updates in {pathToOutputFile}");
|
||||
WriteCsv(toWrite, pathToOutputFile);
|
||||
}
|
||||
|
||||
static IEnumerable<Dictionary<string, string>> ReadCsvFile(string filePath)
|
||||
{
|
||||
var output = new List<Dictionary<string, string>>();
|
||||
|
||||
using (var reader = new StreamReader(filePath))
|
||||
{
|
||||
var line = reader.ReadLine();
|
||||
if (line == null)
|
||||
return output;
|
||||
|
||||
var fieldNamesList = line.Split(',');
|
||||
// Trim the double quotes
|
||||
fieldNamesList = fieldNamesList.Select(x => x.Replace("\"", "")).ToArray();
|
||||
|
||||
line = reader.ReadLine();
|
||||
|
||||
while (null != line)
|
||||
{
|
||||
var dict = new Dictionary<string, string>();
|
||||
|
||||
var values = line.Split(',');
|
||||
// Trim the double quotes
|
||||
values = values.Select(x => x.Replace("\"", "")).ToArray();
|
||||
|
||||
for (long idx = 0; idx < fieldNamesList.Length; idx++)
|
||||
{
|
||||
dict.Add(fieldNamesList[idx], values[idx]);
|
||||
}
|
||||
|
||||
output.Add(dict);
|
||||
|
||||
line = reader.ReadLine();
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
static void WriteCsv (IReadOnlyList<Dictionary<string, string>> input, string filePath)
|
||||
{
|
||||
//Keys should be uniform
|
||||
var keys = input[0].Keys;
|
||||
using (var writer = new StreamWriter(filePath))
|
||||
{
|
||||
writer.WriteLine(string.Join("\t", keys));
|
||||
foreach (var item in input)
|
||||
{
|
||||
writer.WriteLine(string.Join("\t", item.Values));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 57946af1ff629459eb082256509c76d0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,26 @@
|
|||
Shotgun CSV Import Export
|
||||
--------------------------
|
||||
|
||||
This sample shows how to create a timeline in Unity using a shot sequence from a Shotgun CSV export and export back modifications.
|
||||
|
||||
### How to install
|
||||
|
||||
* Import the sample via Package Manager UI
|
||||
* This will import in your Assets folder :
|
||||
* CSVImportExport.cs : a sample script demonstrating how to simply import / export a Shotgun CSV file
|
||||
* shot.csv : a shotgun csv export sample, used in the import.
|
||||
|
||||
### How to test
|
||||
|
||||
* Go to `Window > Film-TV toolbox > Samples > Shotgun` and select `Import CSV`
|
||||
* This creates a Timeline Asset (see shotgun_imported_timeline in the sample folder) from the `shot.csv` sample file
|
||||
|
||||
* Make edits to the Timeline asset
|
||||
|
||||
* Go to `Window > Film-TV toolbox > Samples > Shotgun` and select `Export CSV`:
|
||||
* See export_from_unity.csv in the sample folder
|
||||
|
||||
### Limitations
|
||||
|
||||
* Having commas in fields (e.g.: `Opening sequence, part 2`) will confuse the parser
|
||||
* Having duplicate column names will cause errors due to duplicate keys
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 266585094e33f4ce490787b46930126f
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,6 @@
|
|||
"Id","Shot Code","Thumbnail","Status","Description","Sequence","Open Notes Count","Cut In","Cut Out","Project",
|
||||
"1171","Seq01_Shot01","","ip","Overview","Seq01","6","0","130","Sample Project",
|
||||
"1172","Seq01_Shot02","","wtg","Closing In","Seq01","2","131","262","Sample Project",
|
||||
"1173","Seq01_Shot03","","wtg","Character Shown","Seq01","0","263","433","Sample Project",
|
||||
"1174","Seq01_Shot04","","wtg","Character Runs","Seq01","1","434","597","Sample Project",
|
||||
"1175","Seq01_Shot05","","wtg","Character Jumps","Seq01","0","598","729","Sample Project",
|
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a256f5e1e58be426883e6afdeab395ec
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"name": "Unity.Film-TV.Toolbox.Samples",
|
||||
"references": [
|
||||
"Unity.Film-TV.Toolbox.Editor",
|
||||
"Unity.Timeline"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": []
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 274e5bcbf8c1742a4b6bfe2052956bb7
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 22c3b412315274363a443efa33fcab44
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"createSeparatePackage": true
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2bf2e1267c5454f6d97de33b29f69e92
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,37 @@
|
|||
using UnityEngine;
|
||||
using NUnit.Framework;
|
||||
using System.Linq;
|
||||
using UnityEditor.FilmTV.Toolbox;
|
||||
using UnityEditor.SceneManagement;
|
||||
|
||||
class MaterialRemapperTest
|
||||
{
|
||||
MaterialRemapperModel m_Model;
|
||||
|
||||
[Test, Description("Test GetMeshCount returns the created meshes count")]
|
||||
public void TestMeshListCount() {
|
||||
Assert.That(m_Model.GetMeshCount() == 3);
|
||||
}
|
||||
|
||||
[Test, Description("Test GetUniqueMeshList returns a list which size corresponds to unique meshes count")]
|
||||
public void TestUniqueMeshListCount() {
|
||||
Assert.That(m_Model.GetUniqueMeshList().Count == 2);
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
EditorSceneManager.NewScene(NewSceneSetup.DefaultGameObjects);
|
||||
// Create two GOs from the same source mesh
|
||||
GameObject.CreatePrimitive(PrimitiveType.Cube);
|
||||
GameObject.CreatePrimitive(PrimitiveType.Cube);
|
||||
// Create a GO from another mesh
|
||||
GameObject.CreatePrimitive(PrimitiveType.Sphere);
|
||||
|
||||
m_Model = ScriptableObject.CreateInstance<MaterialRemapperModel>();
|
||||
m_Model.hideFlags = HideFlags.DontSave;
|
||||
|
||||
var transforms = GameObject.FindObjectsOfType<MeshRenderer>().Select(X => X.transform);
|
||||
m_Model.FindMeshesAndMaterials(transforms.ToList());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 253abc0de9c6d4c3aa344523585daff9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,54 @@
|
|||
using System.IO;
|
||||
using UnityEngine;
|
||||
using NUnit.Framework;
|
||||
using UnityEditor.FilmTV.Toolbox;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
class PackageUtilsTest
|
||||
{
|
||||
[Test, Description("Test getting a relative path from a base with no trailing slash")]
|
||||
[UnityPlatform(exclude = new[] {RuntimePlatform.WindowsEditor})] // URIs require a <drive>:\\ on Windows, see UriFormatException
|
||||
public void TestRelativeFolderPathNoTrailingSlash()
|
||||
{
|
||||
var res = PackageUtils.GetRelativeFolderPath("/path/to/folder", "/path/to/folder/subfolder/file.ext");
|
||||
Assert.That(res == "subfolder");
|
||||
}
|
||||
|
||||
[Test, Description("Test getting a relative Windows path from a base with no trailing slash")]
|
||||
public void TestRelativeFolderPathNoTrailingSlashWindows()
|
||||
{
|
||||
var res = PackageUtils.GetRelativeFolderPath("C:\\path\\to\\folder", "C:\\path\\to\\folder\\subfolder\\file.ext");
|
||||
Assert.That(res == "subfolder");
|
||||
}
|
||||
|
||||
[Test, Description("Test getting a relative path from a base with a trailing slash")]
|
||||
[UnityPlatform(exclude = new[] {RuntimePlatform.WindowsEditor})] // URIs require a <drive>:\\ on Windows, see UriFormatException
|
||||
public void TestRelativeFolderPathTrailingSlash()
|
||||
{
|
||||
var res = PackageUtils.GetRelativeFolderPath("/path/to/folder/", "/path/to/folder/subfolder/file.ext");
|
||||
Assert.That(res == "subfolder");
|
||||
}
|
||||
|
||||
[Test, Description("Test getting a relative Windows path from a base with a trailing slash")]
|
||||
public void TestRelativeFolderPathTrailingSlashWindows()
|
||||
{
|
||||
var res = PackageUtils.GetRelativeFolderPath("C:\\path\\to\\folder\\", "C:\\path\\to\\folder\\subfolder\\file.ext");
|
||||
Assert.That(res == "subfolder");
|
||||
}
|
||||
|
||||
[Test, Description("Test Unrelated paths")]
|
||||
[UnityPlatform(exclude = new[] {RuntimePlatform.WindowsEditor})] // URIs require a <drive>:\\ on Windows, see UriFormatException
|
||||
public void TestUnrelatedPaths()
|
||||
{
|
||||
var res = PackageUtils.GetRelativeFolderPath("/another/path/to/folder/", "/path/to/folder/subfolder/file.ext");
|
||||
Assert.That(res == "../../../../path/to/folder/subfolder");
|
||||
}
|
||||
|
||||
[Test, Description("Test Unrelated paths on Windows")]
|
||||
public void TestUnrelatedPathsWindows()
|
||||
{
|
||||
const string folderPath = "D:\\path\\to\\folder\\subfolder";
|
||||
var res = PackageUtils.GetRelativeFolderPath("C:\\path\\to\\folder\\", folderPath + "\\file.ext");
|
||||
Assert.That(res == folderPath.Replace('\\', Path.DirectorySeparatorChar));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 55ebf65f6978a4eeda8100cf270a4fd7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"name": "Unity.Film-TV.Toolbox.EditorTests",
|
||||
"references": [
|
||||
"Unity.Film-TV.Toolbox.Editor"
|
||||
],
|
||||
"optionalUnityReferences": [
|
||||
"TestAssemblies"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": []
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 390d2ccf3930e4bb8b96baf024f9cecd
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"name": "com.unity.film-tv.toolbox",
|
||||
"displayName":"Film and TV Toolbox",
|
||||
"version": "0.1.0-preview.0",
|
||||
"unity": "2018.3",
|
||||
"description": "This package is a collection of experimental, proof of concept or helper tools for Film / TV productions.",
|
||||
"keywords": ["film", "TV", "Tools", "Samples"],
|
||||
"dependencies": {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fea8078c0aae24ff89b99a182a1985db
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Загрузка…
Ссылка в новой задаче