Skip to content

Commit

Permalink
feat: Add Line3D mesh component [flame_3d]
Browse files Browse the repository at this point in the history
  • Loading branch information
luanpotter committed Dec 15, 2024
1 parent 4c5f726 commit b76c95d
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 0 deletions.
85 changes: 85 additions & 0 deletions packages/flame_3d/lib/src/components/line_3d.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import 'dart:math' as math;
import 'dart:ui';

import 'package:flame_3d/components.dart';
import 'package:flame_3d/game.dart';
import 'package:flame_3d/resources.dart';

class Line3D extends MeshComponent {
Line3D._({
required double radius,
required double height,
required Color color,
}) : super(
mesh: CylinderMesh(
radius: radius,
height: height,
material: SpatialMaterial()..albedoColor = color,
),
);

factory Line3D.generate({
required Vector3 start,
required Vector3 end,
required Color color,
double radius = 0.01,
}) {
final line = Line3D._(
radius: radius,
height: start.distanceTo(end),
color: color,
);
line.transform.setFrom(_calculateTransform(start, end));
return line;
}

static Transform3D _calculateTransform(
Vector3 start,
Vector3 end,
) {
final direction = end - start;
final length = direction.length;

final bottomCenter = Vector3(0, -length / 2, 0);
final topCenter = Vector3(0, length / 2, 0);

final translation = start - bottomCenter;

final rotation = _calculateRotationMatrix(
bottomCenter: translation + bottomCenter,
topCenter: translation + topCenter,
target: end,
);

final translationMatrix = Matrix4.translation(translation);
final rotationMatrix = _rotateAroundPoint(rotation, start);
final transform = rotationMatrix.multiplied(translationMatrix);

return Transform3D.fromMatrix4(transform);
}

static Matrix4 _calculateRotationMatrix({
required Vector3 bottomCenter,
required Vector3 topCenter,
required Vector3 target,
}) {
final origin = (topCenter - bottomCenter).normalized();
final dest = (target - bottomCenter).normalized();

final normal = origin.cross(dest);
if (normal.length == 0) {
return Matrix4.identity();
}

final dotProduct = origin.dot(dest);
final angle = math.acos(dotProduct);

return Matrix4.identity()..rotate(normal, angle);
}

static Matrix4 _rotateAroundPoint(Matrix4 rotation, Vector3 point) {
return Matrix4.translation(point)
.multiplied(rotation)
.multiplied(Matrix4.translation(-point));
}
}
22 changes: 22 additions & 0 deletions packages/flame_3d/test/components/line_3d_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import 'dart:ui';

import 'package:flame_3d/core.dart';
import 'package:flame_3d/src/components/line_3d.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
group('Line 3D Mesh Component', () {
test('can create line', () {
final line = Line3D.generate(
start: Vector3(0, -1, 0),
end: Vector3(0, 1, 0),
color: const Color(0xFFFFFFFF),
);

expect(
line.transform.transformMatrix,
equals(Matrix4.identity()),
);
});
});
}

0 comments on commit b76c95d

Please sign in to comment.