Merge pull request #7 from Unity-Technologies/dev_Package_FTV-19

Integrate Shotgun CSV example as a package samples (FTV-19)
This commit is contained in:
Marie FETIVEAU 2019-04-10 16:21:31 -04:00 коммит произвёл GitHub
Родитель ed95ac79b2 155c2cac01
Коммит bc3958eb1e
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
29 изменённых файлов: 435 добавлений и 157 удалений

1
ShotgunImportExport/.gitignore поставляемый
Просмотреть файл

@ -1 +0,0 @@
*.meta

Двоичный файл не отображается.

Просмотреть файл

@ -1,20 +0,0 @@
Shotgun CSV Import Export
==========================
This is a simplified API example of how to create a timeline in Unity using a shot sequence from Shotgun.
How to use
--------
* Create a new project
* Import the [package](Bin/ShotgunImportExport.unitypackage) into your project
* Then through the menu `Window > Film-TV toolbox > Shotgun > Import CSV` import the example csv file
* Alternatively, change the `k_pathToFile` and `k_importFileName` fields to the file you want to use
* Make edits to the timeline asset
* Then through the menu `Window > Film-TV toolbox > Shotgun > Import CSV` export to Shotgun-compatible tab-separated values. This will create a file name `export_from_unity.csv` in the same directory as the imported CSV file
* Use the import function of Shotgun to import the edits into your sequence
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

30
ShotgunSamples/README.md Normal file
Просмотреть файл

@ -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

Двоичные данные
ShotgunSamples/ShotgunCSVImportExport.unitypackage Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -2,4 +2,5 @@
upm-ci~/**
.Editor/**
.yamato/**
*.zip*
*.zip*
TestRunnerOptions.json

Просмотреть файл

@ -3,17 +3,19 @@ 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
### 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.
@ -21,3 +23,40 @@ How to Use
* 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

Двоичные данные
com.unity.film-tv.toolbox/Documentation~/images/SamplesImport.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 93 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 81 KiB

Просмотреть файл

@ -4,7 +4,7 @@ using System.Linq;
using UnityEngine;
using UnityEngine.Rendering;
namespace UnityEditor.Formats.Alembic
namespace UnityEditor.FilmTV.Toolbox
{
[Serializable]
public class MaterialRemapperModel : ScriptableObject

Просмотреть файл

@ -4,7 +4,7 @@ using System.Linq;
using UnityEngine;
using Object = UnityEngine.Object;
namespace UnityEditor.Formats.Alembic
namespace UnityEditor.FilmTV.Toolbox
{
[Serializable]
public class MaterialRemapperView : EditorWindow

Просмотреть файл

@ -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:

Просмотреть файл

@ -5,14 +5,20 @@ This repository is a collection of experimental, proof of concept or helper tool
Prerequistes
---------------
* >= 2018.3
* Windows / OSX
* 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
---------------

Просмотреть файл

@ -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."
}

Просмотреть файл

@ -1,125 +1,129 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using UnityEngine;
using UnityEngine.Timeline;
using UnityEngine.Playables;
using UnityEditor;
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 k_pathToFile = Path.Combine("Assets", "CsvImportExport", "Editor");
const string k_timelineObjectName = "Sample Shotgun CSV timeline";
[UnityEditor.MenuItem("Window/Film-TV toolbox/Shotgun/Import CSV")]
public static void ImportCsv ()
{
TimelineAsset timeline;
timeline = ScriptableObject.CreateInstance("TimelineAsset") as TimelineAsset;
timeline.name = k_timelineObjectName;
timeline.editorSettings.fps = k_FPS;
ControlTrack track = timeline.CreateTrack<ControlTrack>(null, "");
foreach (var row in ReadCsvFile(Path.Combine(k_pathToFile, k_importFileName)))
{
TimelineClip clip = track.CreateClip<ControlPlayableAsset>();
ControlPlayableAsset 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);
}
AssetDatabase.CreateAsset(timeline, Path.Combine(k_pathToFile, k_timelineAssetName ));
}
[UnityEditor.MenuItem("Window/Film-TV toolbox/Shotgun/Export CSV")]
public static void ExportCsv()
{
// Get the actual timeline object
var timelineAsset = AssetDatabase.LoadAssetAtPath<TimelineAsset>(Path.Combine(k_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>>();
TrackAsset 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;
ControlPlayableAsset 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(k_pathToFile, k_exportFileName);
Debug.Log(pathToOutputFile);
WriteCsv(toWrite, pathToOutputFile);
}
private static List<Dictionary<string, string>> ReadCsvFile(string filePath)
{
var output = new List<Dictionary<string, string>>();
using (var reader = new StreamReader(filePath))
{
var fieldNamesList = reader.ReadLine().Split(',');
// Trim the double quotes
fieldNamesList = fieldNamesList.Select(x => x.Replace("\"", "")).ToArray();
string 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 (Int64 idx = 0; idx < fieldNamesList.Length; idx++)
{
dict.Add(fieldNamesList[idx], values[idx]);
}
output.Add(dict);
line = reader.ReadLine();
}
}
return output;
}
private static void WriteCsv (List<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));
}
}
}
}
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,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:

Просмотреть файл

@ -1,10 +1,10 @@
using UnityEngine;
using NUnit.Framework;
using System.Linq;
using UnityEditor.Formats.Alembic;
using UnityEditor.FilmTV.Toolbox;
using UnityEditor.SceneManagement;
class EditorExampleTest
class MaterialRemapperTest
{
MaterialRemapperModel m_Model;

Просмотреть файл

@ -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: