fix(camera-ai): smooth generated camera curves

This commit is contained in:
KINDNICK
2026-08-09 16:33:02 +09:00
parent 5a2e95485e
commit b78c6319b6
18 changed files with 4078 additions and 418 deletions
+158 -48
View File
@@ -4169,31 +4169,122 @@ namespace Streamingle.Editor
{
var projectRoot = Directory.GetParent(Application.dataPath)?.FullName
?? Environment.CurrentDirectory;
return AICameraCliRunner.ResolveExecutable(
return ResolveCliExecutablePath(
ignoreConfigured ? string.Empty : _cliExecutable,
_cwAiRoot,
projectRoot);
projectRoot,
ResolvePhysicalPackageRoot());
}
internal static string ResolveCliExecutablePath(
string configuredExecutable,
string cwAiRoot,
string projectRoot,
string packageRoot)
{
var normalizedConfigured = TryGetFullPath(configuredExecutable);
if (!string.IsNullOrWhiteSpace(normalizedConfigured) &&
!IsCameraAiPackageCachePath(normalizedConfigured) &&
File.Exists(normalizedConfigured))
{
// A valid path outside PackageCache was explicitly selected by
// the user and must remain authoritative.
return normalizedConfigured;
}
var normalizedPackageRoot = TryGetFullPath(packageRoot);
if (!string.IsNullOrWhiteSpace(normalizedPackageRoot))
{
var packagedWorker = Path.Combine(
normalizedPackageRoot,
"Tools~",
"CWCameraWorker",
AICameraCliRunner.ExecutableName);
if (File.Exists(packagedWorker))
{
return Path.GetFullPath(packagedWorker);
}
packagedWorker = Path.Combine(
normalizedPackageRoot,
"Tools~",
AICameraCliRunner.ExecutableName);
if (File.Exists(packagedWorker))
{
return Path.GetFullPath(packagedWorker);
}
}
// Never fall back to a serialized worker or data root from an old
// Git package revision merely because Unity has not evicted that
// PackageCache directory yet.
var safeConfigured = IsCameraAiPackageCachePath(configuredExecutable)
? string.Empty
: normalizedConfigured;
var safeCwAiRoot = IsCameraAiPackageCachePath(cwAiRoot)
? string.Empty
: TryGetFullPath(cwAiRoot);
return AICameraCliRunner.ResolveExecutable(
safeConfigured,
safeCwAiRoot,
projectRoot,
normalizedPackageRoot);
}
internal static string ResolveDefaultCwAiRoot(
string projectRoot,
string configuredRoot)
{
return ResolveDefaultCwAiRoot(
projectRoot,
configuredRoot,
ResolvePhysicalPackageRoot());
}
internal static string ResolveDefaultCwAiRoot(
string projectRoot,
string configuredRoot,
string packageRoot)
{
var normalizedProjectRoot = string.IsNullOrWhiteSpace(projectRoot)
? Environment.CurrentDirectory
: Path.GetFullPath(projectRoot);
var normalizedConfigured = TryGetFullPath(configuredRoot);
if (!string.IsNullOrWhiteSpace(normalizedConfigured) &&
!IsCameraAiPackageCachePath(normalizedConfigured) &&
IsGenerationLibraryRoot(normalizedConfigured))
{
// Preserve a valid repository or data library that the user
// explicitly selected outside Unity's PackageCache.
return normalizedConfigured;
}
var candidates = new List<string>();
// Prefer the self-contained package, including Unity's resolved
// Git PackageCache path. A stale serialized external CW-AI root
// must not silently override the bundled reference library.
candidates.AddRange(EnumeratePackagedRuntimeRoots(normalizedProjectRoot));
candidates.Add(configuredRoot);
candidates.Add(normalizedProjectRoot);
var normalizedPackageRoot = TryGetFullPath(packageRoot);
if (!string.IsNullOrWhiteSpace(normalizedPackageRoot))
{
candidates.Add(Path.Combine(
normalizedPackageRoot,
"RuntimeData~"));
}
// This logical package path supports embedded/local packages when
// FileUtil cannot resolve a physical path during early domain load.
candidates.Add(Path.Combine(
Directory.GetParent(normalizedProjectRoot)?.FullName ??
normalizedProjectRoot,
"CW-AI"));
candidates.Add(Environment.CurrentDirectory);
"Packages",
"com.mingle.cw-ai",
"RuntimeData~"));
candidates.AddRange(new[]
{
normalizedProjectRoot,
Path.Combine(
Directory.GetParent(normalizedProjectRoot)?.FullName ??
normalizedProjectRoot,
"CW-AI"),
Environment.CurrentDirectory
});
foreach (var candidate in candidates)
{
@@ -4224,34 +4315,47 @@ namespace Streamingle.Editor
"CW-AI");
}
private static IEnumerable<string> EnumeratePackagedRuntimeRoots(
string projectRoot)
private static string ResolvePhysicalPackageRoot()
{
yield return Path.Combine(
projectRoot,
"Packages",
"com.mingle.cw-ai",
"RuntimeData~");
var packageCache = Path.Combine(projectRoot, "Library", "PackageCache");
if (!Directory.Exists(packageCache))
{
yield break;
}
IEnumerable<string> matches;
try
{
matches = Directory.EnumerateDirectories(
packageCache,
"com.mingle.cw-ai@*",
SearchOption.TopDirectoryOnly);
return TryGetFullPath(FileUtil.GetPhysicalPath(
"Packages/com.mingle.cw-ai"));
}
catch (Exception)
{
yield break;
return string.Empty;
}
foreach (var match in matches.OrderByDescending(path => path))
}
private static bool IsCameraAiPackageCachePath(string candidate)
{
var fullPath = TryGetFullPath(candidate);
if (string.IsNullOrWhiteSpace(fullPath))
{
yield return Path.Combine(match, "RuntimeData~");
return false;
}
var normalized = fullPath.Replace('\\', '/');
return normalized.IndexOf(
"/Library/PackageCache/com.mingle.cw-ai@",
StringComparison.OrdinalIgnoreCase) >= 0;
}
private static string TryGetFullPath(string candidate)
{
if (string.IsNullOrWhiteSpace(candidate))
{
return string.Empty;
}
try
{
return Path.GetFullPath(candidate.Trim());
}
catch (Exception)
{
return string.Empty;
}
}
@@ -4322,26 +4426,32 @@ namespace Streamingle.Editor
currentRoot = string.Empty;
}
}
if (string.Equals(
currentRoot.TrimEnd('\\', '/'),
resolvedRoot.TrimEnd('\\', '/'),
var previousRoot = _cwAiRoot;
var repairedLibraryRoot = !string.Equals(
currentRoot.TrimEnd('\\', '/'),
resolvedRoot.TrimEnd('\\', '/'),
StringComparison.OrdinalIgnoreCase);
if (repairedLibraryRoot)
{
_cwAiRoot = resolvedRoot;
AppendLog(
"[library-root-auto-repair] " +
$"{previousRoot} -> {_cwAiRoot}");
}
var previousExecutable = _cliExecutable;
var resolvedExecutable = ResolveCliExecutable();
if (!string.Equals(
TryGetFullPath(previousExecutable),
TryGetFullPath(resolvedExecutable),
StringComparison.OrdinalIgnoreCase))
{
return false;
_cliExecutable = resolvedExecutable;
AppendLog(
"[worker-path-auto-repair] " +
$"{previousExecutable} -> {_cliExecutable}");
}
var previousRoot = _cwAiRoot;
_cwAiRoot = resolvedRoot;
if (string.IsNullOrWhiteSpace(_cliExecutable) ||
!File.Exists(_cliExecutable))
{
_cliExecutable = ResolveCliExecutable(true);
}
AppendLog(
"[library-root-auto-repair] " +
$"{previousRoot} -> {_cwAiRoot}");
return true;
return repairedLibraryRoot;
}
private static string ExistingDirectoryOrFallback(
File diff suppressed because it is too large Load Diff