320 lines
7.2 KiB
C#
320 lines
7.2 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using Godot;
|
|
using System;
|
|
|
|
|
|
|
|
namespace Rokojori
|
|
{
|
|
[Tool]
|
|
[GlobalClass]
|
|
public partial class MultiBaker:Node
|
|
{
|
|
[Export]
|
|
public bool initialize;
|
|
|
|
[Export]
|
|
public bool setupViews;
|
|
|
|
|
|
public enum BakeMode
|
|
{
|
|
Cylindric_Billboard
|
|
}
|
|
|
|
[Export]
|
|
public BakeMode bakeMode;
|
|
|
|
[Export]
|
|
public Node3D sourceTarget;
|
|
|
|
[Export]
|
|
public Node outputTarget;
|
|
|
|
|
|
[ExportGroup( "Camera Settings")]
|
|
[Export]
|
|
public Baker.CameraDistanceDetectionType distanceDetectionType = Baker.CameraDistanceDetectionType.Automatic_Distance_Detection;
|
|
|
|
[Export]
|
|
public float customDistance = 50;
|
|
|
|
[Export]
|
|
public float cameraZoom = 1;
|
|
|
|
[Export]
|
|
public Baker.CameraFOVMode fovMode = Baker.CameraFOVMode.Compute_Fov_With_Distance;
|
|
[Export]
|
|
public float originalFOV = 75;
|
|
[Export]
|
|
public float fovPlacingDistance = 200;
|
|
[Export]
|
|
public float customFOV = 75;
|
|
|
|
[Export]
|
|
public Baker.MeshMode meshMode = Baker.MeshMode.World_Scale;
|
|
|
|
|
|
[ExportGroup("Cylindric Billboard")]
|
|
|
|
[Export]
|
|
public int cylinderSides = 4;
|
|
[Export]
|
|
public bool cylinderTop = false;
|
|
[Export]
|
|
public bool cylinderBottom = false;
|
|
[Export]
|
|
public float cylinderSideOffset = 0;
|
|
[Export]
|
|
public float cylinderTopOffset = 0.5f;
|
|
[Export]
|
|
public float cylinderBottomOffset = 0.5f;
|
|
[Export]
|
|
public MeshInstance3D cylinderMesh;
|
|
|
|
|
|
[ExportGroup("Viewport")]
|
|
[Export]
|
|
public Vector2 textureSize = new Vector2( 2048, 2048 );
|
|
|
|
[ExportGroup("Debugging")]
|
|
|
|
[Export]
|
|
public SubViewport X_bakingViewport;
|
|
|
|
[Export]
|
|
public Node3D X_bakingTargetContainer;
|
|
|
|
[Export]
|
|
public Node X_views;
|
|
|
|
[Export]
|
|
public WorldEnvironment X_worldEnvironment;
|
|
|
|
public override void _Process( double delta )
|
|
{
|
|
if ( initialize )
|
|
{
|
|
initialize = false;
|
|
Initialize();
|
|
}
|
|
|
|
if ( setupViews )
|
|
{
|
|
setupViews = false;
|
|
CreateViews();
|
|
SetupViews();
|
|
}
|
|
}
|
|
|
|
public void Initialize()
|
|
{
|
|
if ( outputTarget == null )
|
|
{
|
|
outputTarget = this;
|
|
}
|
|
|
|
Nodes.RemoveAndDeleteChildren( outputTarget );
|
|
|
|
X_bakingViewport = outputTarget.CreateChild<SubViewport>( "Multi Baker Viewport" );
|
|
|
|
X_bakingViewport.Size = (Vector2I) textureSize;
|
|
X_bakingViewport.OwnWorld3D = true;
|
|
X_bakingViewport.TransparentBg = true;
|
|
|
|
X_worldEnvironment = X_bakingViewport.CreateChild<WorldEnvironment>( "Multi Baker Environment" );
|
|
X_worldEnvironment.Environment = new Godot.Environment();
|
|
X_worldEnvironment.Environment.AmbientLightSource = Godot.Environment.AmbientSource.Color;
|
|
X_worldEnvironment.Environment.AmbientLightColor = HSLColor.white;
|
|
|
|
X_bakingTargetContainer = X_bakingViewport.CreateChild<Node3D>( "Target Container" );
|
|
|
|
X_views = X_bakingViewport.CreateChild<Node>( "Views" );
|
|
|
|
sourceTarget.DeepCopyTo( X_bakingTargetContainer );
|
|
|
|
}
|
|
|
|
public int GetNumViews()
|
|
{
|
|
if ( BakeMode.Cylindric_Billboard == bakeMode )
|
|
{
|
|
var cylinderViews = cylinderSides;
|
|
|
|
if ( cylinderBottom )
|
|
{
|
|
cylinderViews ++;
|
|
}
|
|
|
|
if ( cylinderTop )
|
|
{
|
|
cylinderViews ++;
|
|
}
|
|
|
|
return cylinderViews;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
List<Baker> _bakers;
|
|
|
|
public void CreateViews()
|
|
{
|
|
Nodes.RemoveAndDeleteChildren( X_views );
|
|
|
|
var numViews = GetNumViews();
|
|
|
|
_bakers = new List<Baker>();
|
|
|
|
for ( int i = 0; i < numViews; i++ )
|
|
{
|
|
var userIndex = ( i + 1 );
|
|
var bakingView = X_views.CreateChild<SubViewport>( "Baking View " + userIndex );
|
|
bakingView.TransparentBg = true;
|
|
|
|
var bakingCamera = bakingView.CreateChild<Camera3D>( "Camera View " + userIndex );
|
|
var baker = bakingView.CreateChild<Baker>( "Baker " + userIndex );
|
|
|
|
baker.camera = bakingCamera;
|
|
baker.target = X_bakingTargetContainer;
|
|
baker.viewport = bakingView;
|
|
|
|
baker.update = true;
|
|
|
|
_bakers.Add( baker );
|
|
}
|
|
}
|
|
|
|
public void SetupViews()
|
|
{
|
|
if ( BakeMode.Cylindric_Billboard == bakeMode )
|
|
{
|
|
CreateCylinderBillboardView();
|
|
}
|
|
}
|
|
|
|
Sphere _targetBoundingSphere;
|
|
|
|
Sphere targetBoundingSphere
|
|
{
|
|
get
|
|
{
|
|
if ( _targetBoundingSphere == null )
|
|
{
|
|
ComputeBoundingSphere();
|
|
}
|
|
|
|
return _targetBoundingSphere;
|
|
}
|
|
}
|
|
|
|
void ComputeBoundingSphere()
|
|
{
|
|
var worldBounds = X_bakingTargetContainer.GetWorldBounds();
|
|
_targetBoundingSphere = Sphere.ContainingBox( worldBounds );
|
|
}
|
|
|
|
float GetCameraFOV()
|
|
{
|
|
if ( Baker.CameraFOVMode.Custom_Fov == fovMode )
|
|
{
|
|
return customFOV;
|
|
}
|
|
|
|
if ( Baker.CameraFOVMode.Keep_Fov == fovMode )
|
|
{
|
|
return originalFOV;
|
|
}
|
|
|
|
return Cameras.ComputeFOVForBillboard( originalFOV, targetBoundingSphere.radius, fovPlacingDistance );
|
|
}
|
|
|
|
float GetCameraDistance()
|
|
{
|
|
if ( Baker.CameraDistanceDetectionType.Custom_Distance == distanceDetectionType )
|
|
{
|
|
return customDistance;
|
|
}
|
|
|
|
var fov = GetCameraFOV();
|
|
|
|
return Cameras.ComputeCameraFrameFittingDistance( fov, targetBoundingSphere.radius / cameraZoom );
|
|
}
|
|
|
|
float GetOutputScale()
|
|
{
|
|
var fov = GetCameraFOV();
|
|
var distance = GetCameraDistance();
|
|
|
|
return Cameras.ComputeCameraFittingScale( fov, distance );
|
|
}
|
|
|
|
void CreateCylinderBillboardView()
|
|
{
|
|
_targetBoundingSphere = null;
|
|
var fov = GetCameraFOV();
|
|
var distance = GetCameraDistance();
|
|
var outputScale = GetOutputScale();
|
|
|
|
_bakers.ForEach(
|
|
b =>
|
|
{
|
|
b.useCustomFOV = true;
|
|
b.customFOV = fov;
|
|
|
|
b.useCustomDistance = true;
|
|
b.customDistance = distance;
|
|
}
|
|
);
|
|
|
|
var index = 0;
|
|
var mg = new MeshGeometry();
|
|
|
|
var numTextures = ( cylinderTop ? 1 : 0 ) + ( cylinderBottom ? 1 : 0 ) + cylinderSides;
|
|
var textureAlignment = TextureMerger.ComputeTextureAlignment( numTextures );
|
|
|
|
|
|
if ( cylinderTop )
|
|
{
|
|
_bakers[ index ].yaw = 0;
|
|
_bakers[ index ].pitch = 90f;
|
|
|
|
var uvRectangle = TextureMerger.GetUVRectangle( textureAlignment, index );
|
|
mg.AddQuad( _bakers[ index ].bakingRotation, outputScale, uvRectangle );
|
|
|
|
index ++;
|
|
}
|
|
|
|
if ( cylinderBottom )
|
|
{
|
|
_bakers[ index ].yaw = 0;
|
|
_bakers[ index ].pitch = -90f;
|
|
|
|
var uvRectangle = TextureMerger.GetUVRectangle( textureAlignment, index );
|
|
mg.AddQuad( _bakers[ index ].bakingRotation, outputScale, uvRectangle );
|
|
|
|
index ++;
|
|
}
|
|
|
|
|
|
for ( int i = 0; i < cylinderSides; i++ )
|
|
{
|
|
var angle = ( 360f * i ) / (float) cylinderSides;
|
|
_bakers[ index + i ].yaw = angle;
|
|
_bakers[ index + i ].pitch = 0;
|
|
|
|
var uv = TextureMerger.GetUVRectangle( textureAlignment, index + 1);
|
|
mg.AddQuad( _bakers[ index + i ].bakingRotation, outputScale, uv );
|
|
}
|
|
|
|
if ( cylinderMesh != null )
|
|
{
|
|
cylinderMesh.Mesh = mg.GenerateMesh();
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
} |