Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
using SharpGLTF.Geometry;
using SharpGLTF.Geometry.VertexTypes;
namespace SharpGLTF.Schema2
{
public static partial class Toolkit
{
#region fluent creation
public static Node WithLocalTransform(this Node node, Transforms.AffineTransform xform)
{
Guard.NotNull(node, nameof(node));
node.LocalTransform = xform;
return node;
}
public static Node WithLocalTranslation(this Node node, Vector3 translation)
{
Guard.NotNull(node, nameof(node));
var xform = node.LocalTransform;
xform.Translation = translation;
node.LocalTransform = xform;
return node;
}
public static Node WithLocalRotation(this Node node, Quaternion rotation)
{
Guard.NotNull(node, nameof(node));
var xform = node.LocalTransform;
xform.Rotation = rotation;
node.LocalTransform = xform;
return node;
}
public static Node WithLocalScale(this Node node, Vector3 scale)
{
Guard.NotNull(node, nameof(node));
var xform = node.LocalTransform;
xform.Scale = scale;
node.LocalTransform = xform;
return node;
}
public static Node WithMesh(this Node node, Mesh mesh)
{
Guard.NotNull(node, nameof(node));
node.Mesh = mesh;
return node;
}
public static Node WithSkin(this Node node, Skin skin)
{
Guard.NotNull(node, nameof(node));
node.Skin = skin;
return node;
}
public static Node WithSkinBinding(this Node node, Matrix4x4 meshPoseTransform, params Node[] joints)
{
Guard.NotNull(node, nameof(node));
foreach (var j in joints) Guard.MustShareLogicalParent(node, j, nameof(joints));
var skin = node.LogicalParent.CreateSkin();
skin.BindJoints(meshPoseTransform, joints);
node.Skin = skin;
return node;
}
public static Node WithSkinBinding(this Node node, params (Node Joint, Matrix4x4 InverseBindMatrix)[] joints)
{
Guard.NotNull(node, nameof(node));
foreach (var j in joints)
{
Guard.MustShareLogicalParent(node, j.Joint, nameof(joints));
Guard.IsTrue(Matrix4x4.Invert(j.InverseBindMatrix, out Matrix4x4 r), nameof(joints), "Invalid Matrix");
}
var skin = node.LogicalParent.CreateSkin();
skin.BindJoints(joints);
node.Skin = skin;
return node;
}
public static Node WithSkinnedMesh(this Node node, Mesh mesh, Matrix4x4 meshPoseTransform, params Node[] joints)
{
Guard.NotNull(node, nameof(node));
Guard.NotNull(mesh, nameof(mesh));
Guard.NotNull(joints, nameof(joints));
Guard.MustShareLogicalParent(node, mesh, nameof(mesh));
foreach (var j in joints) Guard.MustShareLogicalParent(node, j, nameof(joints));
// TODO: the joints must be visible in the visual tree that contains node.
return node
.WithMesh(mesh)
.WithSkinBinding(meshPoseTransform, joints);
}
public static Node WithSkinnedMesh(this Node node, Mesh mesh, params (Node Joint, Matrix4x4 InverseBindMatrix)[] joints)
{
Guard.NotNull(node, nameof(node));
Guard.NotNull(mesh, nameof(mesh));
Guard.NotNull(joints, nameof(joints));
Guard.MustShareLogicalParent(node, mesh, nameof(mesh));
foreach (var j in joints)
{
Guard.MustShareLogicalParent(node, j.Joint, nameof(joints));
Guard.IsTrue(Matrix4x4.Invert(j.InverseBindMatrix, out Matrix4x4 r), nameof(joints), "Invalid Matrix");
}
// TODO: the joints must be visible in the visual tree that contains node.
return node
.WithMesh(mesh)
.WithSkinBinding(joints);
}
public static Node WithPerspectiveCamera(this Node node, float? aspectRatio, float fovy, float znear, float zfar = float.PositiveInfinity)
{
Guard.NotNull(node, nameof(node));
CameraPerspective.VerifyParameters(aspectRatio, fovy, znear, zfar);
var camera = node.LogicalParent.CreateCamera();
camera.SetPerspectiveMode(aspectRatio, fovy, znear, zfar);
node.Camera = camera;
return node;
}
public static Node WithOrthographicCamera(this Node node, float xmag, float ymag, float znear, float zfar)
{
Guard.NotNull(node, nameof(node));
CameraOrthographic.VerifyParameters(xmag, ymag, znear, zfar);
var camera = node.LogicalParent.CreateCamera();
camera.SetOrthographicMode(xmag, ymag, znear, zfar);
node.Camera = camera;
return node;
}
#endregion
#region evaluation
/// <summary>
/// Finds a <see cref="Node"/> by name in the current graph.
/// </summary>
/// <param name="scene">This <see cref="Scene"/> instance.</param>
/// <param name="predicate">A function to test each <see cref="Node"/> for a condition.</param>
/// <returns>A <see cref="Node"/> instance, or Null.</returns>
public static Node FindNode(this Scene scene, Predicate<Node> predicate)
{
Guard.NotNull(scene, nameof(scene));
Guard.NotNull(predicate, nameof(predicate));
return scene.VisualChildren.FirstOrDefault(n => predicate(n));
}
/// <summary>
/// Finds a <see cref="Node"/> by name in the current graph.
/// </summary>
/// <param name="node">This <see cref="Node"/> instance.</param>
/// <param name="predicate">A function to test each <see cref="Node"/> for a condition.</param>
/// <returns>A <see cref="Node"/> instance, or Null.</returns>
public static Node FindNode(this Node node, Predicate<Node> predicate)
{
Guard.NotNull(node, nameof(node));
Guard.NotNull(predicate, nameof(predicate));
if (predicate(node)) return node;
foreach (var child in node.VisualChildren)
{
var r = child.FindNode(predicate);
if (r != null) return r;
}
return null;
}
/// <summary>
/// Yields a collection of triangles representing the geometry in world space.
/// </summary>
/// /// <param name="scene">A <see cref="Scene"/> instance.</param>
/// <param name="animation">An <see cref="Animation"/> instance, or null.</param>
/// <param name="time">The animation time.</param>
/// <returns>A collection of triangles in world space.</returns>
public static IEnumerable<(IVertexBuilder A, IVertexBuilder B, IVertexBuilder C, Material Material)> EvaluateTriangles(this Scene scene, Animation animation = null, float time = 0)
{
if (scene == null) return Enumerable.Empty<(IVertexBuilder, IVertexBuilder, IVertexBuilder, Material)>();
var instance = Runtime.SceneTemplate
.Create(scene, false)
.CreateInstance();
if (animation == null)
{
instance.Armature.SetPoseTransforms();
}
else
{
instance.Armature.SetAnimationFrame(animation.LogicalIndex, time);
}
var meshes = scene.LogicalParent.LogicalMeshes;
return instance
.DrawableInstances
.Where(item => item.Transform.Visible)
.SelectMany(item => meshes[item.Template.LogicalMeshIndex].EvaluateTriangles(item.Transform));
}
/// <summary>
/// Yields a collection of triangles representing the geometry in world space.
/// </summary>
/// <typeparam name="TvG">The vertex fragment type with Position, Normal and Tangent.</typeparam>
/// <typeparam name="TvM">The vertex fragment type with Colors and Texture Coordinates.</typeparam>
/// <param name="scene">A <see cref="Scene"/> instance.</param>
/// <param name="animation">An <see cref="Animation"/> instance, or null.</param>
/// <param name="time">The animation time.</param>
/// <returns>A collection of triangles in world space.</returns>
public static IEnumerable<(VertexBuilder<TvG, TvM, VertexEmpty> A, VertexBuilder<TvG, TvM, VertexEmpty> B, VertexBuilder<TvG, TvM, VertexEmpty> C, Material Material)> EvaluateTriangles<TvG, TvM>(this Scene scene, Animation animation = null, float time = 0)
where TvG : struct, IVertexGeometry
where TvM : struct, IVertexMaterial
{
if (scene == null) return Enumerable.Empty<(VertexBuilder<TvG, TvM, VertexEmpty>, VertexBuilder<TvG, TvM, VertexEmpty>, VertexBuilder<TvG, TvM, VertexEmpty>, Material)>();
var instance = Runtime.SceneTemplate
.Create(scene, false)
.CreateInstance();
if (animation == null)
{
instance.Armature.SetPoseTransforms();
}
else
{
instance.Armature.SetAnimationFrame(animation.LogicalIndex, time);
}
var meshes = scene.LogicalParent.LogicalMeshes;
return instance
.DrawableInstances
.Where(item => item.Transform.Visible)
.SelectMany(item => meshes[item.Template.LogicalMeshIndex].EvaluateTriangles<TvG, TvM, VertexEmpty>(item.Transform));
}
public static Scenes.SceneBuilder ToSceneBuilder(this Scene srcScene)
{
return Scenes.SceneBuilder.CreateFrom(srcScene);
}
#endregion
}
}
d49ffeb42This file is pinned to the selected release. Download the original to open it in your design tool.