fix: tune camera and humanoid fbx imports
This commit is contained in:
@@ -0,0 +1,291 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
public static class HumanoidAnimationFbxImportSettings
|
||||||
|
{
|
||||||
|
public const string ActorRootPath = "Assets/Game/Art/Actor/";
|
||||||
|
public const string CityboyAvatarPath = "Assets/Game/Art/Actor/cityboy/cityboy_sk.fbx";
|
||||||
|
public const string CityboyAvatarName = "Cityboy_sk Avatar";
|
||||||
|
public const string CityboyHipBoneName = "mixamorig:Hips";
|
||||||
|
|
||||||
|
public static bool ShouldProcessAsset(string assetPath)
|
||||||
|
{
|
||||||
|
string normalizedPath = NormalizeAssetPath(assetPath);
|
||||||
|
|
||||||
|
return normalizedPath.EndsWith(".fbx", StringComparison.OrdinalIgnoreCase)
|
||||||
|
&& normalizedPath.StartsWith(ActorRootPath, StringComparison.OrdinalIgnoreCase)
|
||||||
|
&& !string.Equals(normalizedPath, CityboyAvatarPath, StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ModelImporterClipAnimation ApplyClipSettings(ModelImporterClipAnimation clip)
|
||||||
|
{
|
||||||
|
clip.lockRootRotation = true;
|
||||||
|
clip.keepOriginalOrientation = true;
|
||||||
|
clip.lockRootHeightY = true;
|
||||||
|
return clip;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ModelImporterClipAnimation[] ApplyClipSettings(ModelImporterClipAnimation[] clips)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < clips.Length; i++)
|
||||||
|
{
|
||||||
|
clips[i] = ApplyClipSettings(clips[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return clips;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool ShouldUseCityboyAvatar(string assetPath)
|
||||||
|
{
|
||||||
|
string filePath = ResolveAssetFilePath(assetPath);
|
||||||
|
if (string.IsNullOrEmpty(filePath) || !File.Exists(filePath))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ShouldUseCityboyAvatar(File.ReadAllBytes(filePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool ShouldUseCityboyAvatar(byte[] assetBytes)
|
||||||
|
{
|
||||||
|
if (assetBytes == null || assetBytes.Length == 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] marker = System.Text.Encoding.ASCII.GetBytes(CityboyHipBoneName);
|
||||||
|
for (int i = 0; i <= assetBytes.Length - marker.Length; i++)
|
||||||
|
{
|
||||||
|
bool matched = true;
|
||||||
|
for (int markerIndex = 0; markerIndex < marker.Length; markerIndex++)
|
||||||
|
{
|
||||||
|
if (assetBytes[i + markerIndex] != marker[markerIndex])
|
||||||
|
{
|
||||||
|
matched = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matched)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ModelImporterClipAnimation CreateClipAnimation(TakeInfo takeInfo)
|
||||||
|
{
|
||||||
|
string clipName = string.IsNullOrEmpty(takeInfo.defaultClipName) ? takeInfo.name : takeInfo.defaultClipName;
|
||||||
|
|
||||||
|
return ApplyClipSettings(new ModelImporterClipAnimation
|
||||||
|
{
|
||||||
|
name = clipName,
|
||||||
|
takeName = takeInfo.name,
|
||||||
|
firstFrame = takeInfo.startTime * takeInfo.sampleRate,
|
||||||
|
lastFrame = takeInfo.stopTime * takeInfo.sampleRate
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ModelImporterClipAnimation CreateClipAnimation(AnimationClip animationClip)
|
||||||
|
{
|
||||||
|
float frameRate = animationClip.frameRate > 0f ? animationClip.frameRate : 30f;
|
||||||
|
|
||||||
|
return ApplyClipSettings(new ModelImporterClipAnimation
|
||||||
|
{
|
||||||
|
name = animationClip.name,
|
||||||
|
takeName = animationClip.name,
|
||||||
|
firstFrame = 0f,
|
||||||
|
lastFrame = animationClip.length * frameRate
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string NormalizeAssetPath(string assetPath)
|
||||||
|
{
|
||||||
|
return string.IsNullOrEmpty(assetPath) ? string.Empty : assetPath.Replace('\\', '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ResolveAssetFilePath(string assetPath)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(assetPath))
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Path.IsPathRooted(assetPath) || File.Exists(assetPath))
|
||||||
|
{
|
||||||
|
return assetPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
DirectoryInfo projectRoot = Directory.GetParent(Application.dataPath);
|
||||||
|
return projectRoot == null ? assetPath : Path.Combine(projectRoot.FullName, NormalizeAssetPath(assetPath));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class HumanoidAnimationFbxPostprocessor : AssetPostprocessor
|
||||||
|
{
|
||||||
|
private static readonly HashSet<string> ReimportingAssets = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
private void OnPreprocessModel()
|
||||||
|
{
|
||||||
|
if (!(assetImporter is ModelImporter modelImporter))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!HumanoidAnimationFbxImportSettings.ShouldProcessAsset(assetPath))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
modelImporter.importAnimation = true;
|
||||||
|
modelImporter.animationType = ModelImporterAnimationType.Human;
|
||||||
|
if (HumanoidAnimationFbxImportSettings.ShouldUseCityboyAvatar(assetPath))
|
||||||
|
{
|
||||||
|
Avatar cityboyAvatar = LoadCityboyAvatar();
|
||||||
|
if (cityboyAvatar == null)
|
||||||
|
{
|
||||||
|
Debug.LogWarning(
|
||||||
|
$"[HumanoidAnimationFbxPostprocessor] Cannot find Cityboy avatar at {HumanoidAnimationFbxImportSettings.CityboyAvatarPath}. Skip import settings for {assetPath}.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
modelImporter.avatarSetup = ModelImporterAvatarSetup.CopyFromOther;
|
||||||
|
modelImporter.sourceAvatar = cityboyAvatar;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
modelImporter.avatarSetup = ModelImporterAvatarSetup.CreateFromThisModel;
|
||||||
|
modelImporter.sourceAvatar = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelImporterClipAnimation[] clips = GetAnimationClips(modelImporter);
|
||||||
|
if (clips.Length == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
modelImporter.clipAnimations = HumanoidAnimationFbxImportSettings.ApplyClipSettings(clips);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void OnPostprocessAllAssets(
|
||||||
|
string[] importedAssets,
|
||||||
|
string[] deletedAssets,
|
||||||
|
string[] movedAssets,
|
||||||
|
string[] movedFromAssetPaths)
|
||||||
|
{
|
||||||
|
foreach (string importedAsset in importedAssets)
|
||||||
|
{
|
||||||
|
ConfigureImportedAnimationClips(importedAsset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ConfigureImportedAnimationClips(string assetPath)
|
||||||
|
{
|
||||||
|
if (!HumanoidAnimationFbxImportSettings.ShouldProcessAsset(assetPath))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ReimportingAssets.Remove(assetPath))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(AssetImporter.GetAtPath(assetPath) is ModelImporter modelImporter))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelImporterClipAnimation[] existingClips = modelImporter.clipAnimations;
|
||||||
|
if (existingClips != null && existingClips.Length > 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelImporterClipAnimation[] clips = CreateClipAnimationsFromImportedAssets(assetPath);
|
||||||
|
if (clips.Length == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
modelImporter.clipAnimations = HumanoidAnimationFbxImportSettings.ApplyClipSettings(clips);
|
||||||
|
ReimportingAssets.Add(assetPath);
|
||||||
|
modelImporter.SaveAndReimport();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ModelImporterClipAnimation[] GetAnimationClips(ModelImporter modelImporter)
|
||||||
|
{
|
||||||
|
ModelImporterClipAnimation[] clips = modelImporter.clipAnimations;
|
||||||
|
if (clips != null && clips.Length > 0)
|
||||||
|
{
|
||||||
|
return clips;
|
||||||
|
}
|
||||||
|
|
||||||
|
clips = modelImporter.defaultClipAnimations;
|
||||||
|
if (clips != null && clips.Length > 0)
|
||||||
|
{
|
||||||
|
return clips;
|
||||||
|
}
|
||||||
|
|
||||||
|
TakeInfo[] takes = modelImporter.importedTakeInfos;
|
||||||
|
if (takes == null || takes.Length == 0)
|
||||||
|
{
|
||||||
|
return Array.Empty<ModelImporterClipAnimation>();
|
||||||
|
}
|
||||||
|
|
||||||
|
clips = new ModelImporterClipAnimation[takes.Length];
|
||||||
|
for (int i = 0; i < takes.Length; i++)
|
||||||
|
{
|
||||||
|
clips[i] = HumanoidAnimationFbxImportSettings.CreateClipAnimation(takes[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return clips;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Avatar LoadCityboyAvatar()
|
||||||
|
{
|
||||||
|
Avatar fallbackAvatar = null;
|
||||||
|
UnityEngine.Object[] assets = AssetDatabase.LoadAllAssetsAtPath(HumanoidAnimationFbxImportSettings.CityboyAvatarPath);
|
||||||
|
|
||||||
|
foreach (UnityEngine.Object asset in assets)
|
||||||
|
{
|
||||||
|
if (!(asset is Avatar avatar))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fallbackAvatar == null)
|
||||||
|
{
|
||||||
|
fallbackAvatar = avatar;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.Equals(avatar.name, HumanoidAnimationFbxImportSettings.CityboyAvatarName, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return avatar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fallbackAvatar;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ModelImporterClipAnimation[] CreateClipAnimationsFromImportedAssets(string assetPath)
|
||||||
|
{
|
||||||
|
UnityEngine.Object[] assets = AssetDatabase.LoadAllAssetRepresentationsAtPath(assetPath);
|
||||||
|
var clips = new List<ModelImporterClipAnimation>();
|
||||||
|
|
||||||
|
foreach (UnityEngine.Object asset in assets)
|
||||||
|
{
|
||||||
|
if (asset is AnimationClip animationClip)
|
||||||
|
{
|
||||||
|
clips.Add(HumanoidAnimationFbxImportSettings.CreateClipAnimation(animationClip));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return clips.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: eca73c54c7164f2cb8873812efa969fa
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
using NUnit.Framework;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
public sealed class HumanoidAnimationFbxImportSettingsTests
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void ShouldProcessActorAnimationFbx()
|
||||||
|
{
|
||||||
|
Assert.That(
|
||||||
|
HumanoidAnimationFbxImportSettings.ShouldProcessAsset(
|
||||||
|
"Assets/Game/Art/Actor/Controller/Class/Caster/Standing Walk Forward.fbx"),
|
||||||
|
Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ShouldNotProcessCityboySourceAvatar()
|
||||||
|
{
|
||||||
|
Assert.That(
|
||||||
|
HumanoidAnimationFbxImportSettings.ShouldProcessAsset(
|
||||||
|
HumanoidAnimationFbxImportSettings.CityboyAvatarPath),
|
||||||
|
Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ShouldProcessActorFbxEvenWhenCustomClipAnimationsAreEmpty()
|
||||||
|
{
|
||||||
|
Assert.That(
|
||||||
|
HumanoidAnimationFbxImportSettings.ShouldProcessAsset(
|
||||||
|
"Assets/Game/Art/Actor/Controller/Class/Caster/Standing 2H Magic Area Attack 02.fbx"),
|
||||||
|
Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ShouldNotProcessFbxOutsideActorFolder()
|
||||||
|
{
|
||||||
|
Assert.That(
|
||||||
|
HumanoidAnimationFbxImportSettings.ShouldProcessAsset(
|
||||||
|
"Assets/Res/cityboy_uv2/cityboy_uv2.fbx"),
|
||||||
|
Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ShouldNotUseCityboyAvatarWhenFbxDoesNotContainCityboyHipBone()
|
||||||
|
{
|
||||||
|
Assert.That(
|
||||||
|
HumanoidAnimationFbxImportSettings.ShouldUseCityboyAvatar(
|
||||||
|
new byte[] { 72, 105, 112, 115 }),
|
||||||
|
Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ShouldUseCityboyAvatarWhenFbxContainsCityboyHipBone()
|
||||||
|
{
|
||||||
|
Assert.That(
|
||||||
|
HumanoidAnimationFbxImportSettings.ShouldUseCityboyAvatar(
|
||||||
|
System.Text.Encoding.ASCII.GetBytes("Model::mixamorig:Hips")),
|
||||||
|
Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ApplyClipSettingsUsesOriginalRotationAndBakesRotationAndY()
|
||||||
|
{
|
||||||
|
var clip = new ModelImporterClipAnimation
|
||||||
|
{
|
||||||
|
lockRootRotation = false,
|
||||||
|
keepOriginalOrientation = false,
|
||||||
|
lockRootHeightY = false
|
||||||
|
};
|
||||||
|
|
||||||
|
ModelImporterClipAnimation updated = HumanoidAnimationFbxImportSettings.ApplyClipSettings(clip);
|
||||||
|
|
||||||
|
Assert.That(updated.lockRootRotation, Is.True);
|
||||||
|
Assert.That(updated.keepOriginalOrientation, Is.True);
|
||||||
|
Assert.That(updated.lockRootHeightY, Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ApplyClipSettingsUpdatesEveryClipBeforeWriteback()
|
||||||
|
{
|
||||||
|
var clips = new[]
|
||||||
|
{
|
||||||
|
new ModelImporterClipAnimation { name = "Attack01" },
|
||||||
|
new ModelImporterClipAnimation { name = "Attack02" }
|
||||||
|
};
|
||||||
|
|
||||||
|
ModelImporterClipAnimation[] updated = HumanoidAnimationFbxImportSettings.ApplyClipSettings(clips);
|
||||||
|
|
||||||
|
Assert.That(updated, Has.Length.EqualTo(2));
|
||||||
|
Assert.That(updated[0].lockRootRotation, Is.True);
|
||||||
|
Assert.That(updated[0].keepOriginalOrientation, Is.True);
|
||||||
|
Assert.That(updated[0].lockRootHeightY, Is.True);
|
||||||
|
Assert.That(updated[1].lockRootRotation, Is.True);
|
||||||
|
Assert.That(updated[1].keepOriginalOrientation, Is.True);
|
||||||
|
Assert.That(updated[1].lockRootHeightY, Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void CreateClipAnimationFromTakeInfoUsesTakeFramesAndAppliesRootSettings()
|
||||||
|
{
|
||||||
|
var takeInfo = new TakeInfo
|
||||||
|
{
|
||||||
|
name = "mixamo.com",
|
||||||
|
defaultClipName = "Standing 2H Magic Area Attack 02",
|
||||||
|
startTime = 0f,
|
||||||
|
stopTime = 4.5f,
|
||||||
|
sampleRate = 30f
|
||||||
|
};
|
||||||
|
|
||||||
|
ModelImporterClipAnimation clip = HumanoidAnimationFbxImportSettings.CreateClipAnimation(takeInfo);
|
||||||
|
|
||||||
|
Assert.That(clip.name, Is.EqualTo("Standing 2H Magic Area Attack 02"));
|
||||||
|
Assert.That(clip.takeName, Is.EqualTo("mixamo.com"));
|
||||||
|
Assert.That(clip.firstFrame, Is.EqualTo(0f));
|
||||||
|
Assert.That(clip.lastFrame, Is.EqualTo(135f));
|
||||||
|
Assert.That(clip.lockRootRotation, Is.True);
|
||||||
|
Assert.That(clip.keepOriginalOrientation, Is.True);
|
||||||
|
Assert.That(clip.lockRootHeightY, Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void CreateClipAnimationFromImportedClipUsesClipNameAndLength()
|
||||||
|
{
|
||||||
|
var importedClip = new AnimationClip
|
||||||
|
{
|
||||||
|
name = "Standing 2H Magic Area Attack 02",
|
||||||
|
frameRate = 30f
|
||||||
|
};
|
||||||
|
importedClip.SetCurve(
|
||||||
|
string.Empty,
|
||||||
|
typeof(Transform),
|
||||||
|
"m_LocalPosition.x",
|
||||||
|
new AnimationCurve(new Keyframe(0f, 0f), new Keyframe(4.5f, 0f)));
|
||||||
|
|
||||||
|
ModelImporterClipAnimation clip = HumanoidAnimationFbxImportSettings.CreateClipAnimation(importedClip);
|
||||||
|
|
||||||
|
Assert.That(clip.name, Is.EqualTo("Standing 2H Magic Area Attack 02"));
|
||||||
|
Assert.That(clip.takeName, Is.EqualTo("Standing 2H Magic Area Attack 02"));
|
||||||
|
Assert.That(clip.firstFrame, Is.EqualTo(0f));
|
||||||
|
Assert.That(clip.lastFrame, Is.EqualTo(135f));
|
||||||
|
Assert.That(clip.lockRootRotation, Is.True);
|
||||||
|
Assert.That(clip.keepOriginalOrientation, Is.True);
|
||||||
|
Assert.That(clip.lockRootHeightY, Is.True);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 60252bd67a3943b38f65d188a2128557
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -43,9 +43,9 @@ namespace XGame
|
|||||||
private const float JoystickPadding = 100.0f;
|
private const float JoystickPadding = 100.0f;
|
||||||
private const float JoystickDeadZone = 0.18f;
|
private const float JoystickDeadZone = 0.18f;
|
||||||
private const float JoystickAcquireRadiusMultiplier = 1.6f;
|
private const float JoystickAcquireRadiusMultiplier = 1.6f;
|
||||||
private const float CameraMinDistance = 3.5f;
|
private const float CameraMinDistance = 2.0f;
|
||||||
private const float CameraMaxDistance = 14f;
|
private const float CameraMaxDistance = 8f;
|
||||||
private const float CameraDefaultDistance = 9.5f;
|
private const float CameraDefaultDistance = 4.5f;
|
||||||
private const float CameraMinPitch = 20f;
|
private const float CameraMinPitch = 20f;
|
||||||
private const float CameraMaxPitch = 75f;
|
private const float CameraMaxPitch = 75f;
|
||||||
private const float CameraMouseOrbitSensitivity = 0.2f;
|
private const float CameraMouseOrbitSensitivity = 0.2f;
|
||||||
|
|||||||
@@ -285,7 +285,7 @@ namespace XGame
|
|||||||
sun.type = LightType.Directional;
|
sun.type = LightType.Directional;
|
||||||
sun.color = RuntimeSunColor;
|
sun.color = RuntimeSunColor;
|
||||||
sun.intensity = Mathf.Max(sun.intensity, RuntimeSunIntensity);
|
sun.intensity = Mathf.Max(sun.intensity, RuntimeSunIntensity);
|
||||||
sun.shadows = LightShadows.None;
|
//sun.shadows = LightShadows.None;
|
||||||
sun.transform.rotation = Quaternion.Euler(50f, -30f, 0f);
|
sun.transform.rotation = Quaternion.Euler(50f, -30f, 0f);
|
||||||
RenderSettings.sun = sun;
|
RenderSettings.sun = sun;
|
||||||
return sun;
|
return sun;
|
||||||
|
|||||||
Reference in New Issue
Block a user