Flutter Engine
The Flutter Engine
scene_unittests.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <cmath>
6#include <memory>
7#include <vector>
8
9#include "flutter/fml/mapping.h"
10#include "flutter/testing/testing.h"
23#include "impeller/scene/importer/scene_flatbuffers.h"
25#include "impeller/scene/mesh.h"
27#include "third_party/flatbuffers/include/flatbuffers/verifier.h"
28#include "third_party/imgui/imgui.h"
29
30namespace impeller {
31namespace scene {
32namespace testing {
33
36
37TEST_P(SceneTest, CuboidUnlit) {
38 auto scene_context = std::make_shared<SceneContext>(GetContext());
39
40 Renderer::RenderCallback callback = [&](RenderTarget& render_target) {
41 auto allocator = GetContext()->GetResourceAllocator();
42 auto scene = Scene(scene_context);
43
44 {
45 Mesh mesh;
46
47 auto material = Material::MakeUnlit();
48 material->SetColor(Color::Red());
49
50 Vector3 size(1, 1, 0);
51 mesh.AddPrimitive({Geometry::MakeCuboid(size), std::move(material)});
52
53 Node& root = scene.GetRoot();
54 root.SetLocalTransform(Matrix::MakeTranslation(-size / 2));
55 root.SetMesh(std::move(mesh));
56 }
57
58 // Face towards the +Z direction (+X right, +Y up).
59 auto camera = Camera::MakePerspective(
60 /* fov */ Radians(kPiOver4),
61 /* position */ {2, 2, -5})
62 .LookAt(
63 /* target */ Vector3(),
64 /* up */ {0, 1, 0});
65
66 scene.Render(render_target, camera);
67 return true;
68 };
69
70 OpenPlaygroundHere(callback);
71}
72
73TEST_P(SceneTest, FlutterLogo) {
74 auto allocator = GetContext()->GetResourceAllocator();
75
76 auto mapping =
77 flutter::testing::OpenFixtureAsMapping("flutter_logo_baked.glb.ipscene");
78 ASSERT_NE(mapping, nullptr);
79
80 flatbuffers::Verifier verifier(mapping->GetMapping(), mapping->GetSize());
81 ASSERT_TRUE(fb::VerifySceneBuffer(verifier));
82
83 std::shared_ptr<Node> gltf_scene =
84 Node::MakeFromFlatbuffer(*mapping, *allocator);
85 ASSERT_NE(gltf_scene, nullptr);
86 ASSERT_EQ(gltf_scene->GetChildren().size(), 1u);
87 ASSERT_EQ(gltf_scene->GetChildren()[0]->GetMesh().GetPrimitives().size(), 1u);
88
89 auto scene_context = std::make_shared<SceneContext>(GetContext());
90 auto scene = Scene(scene_context);
91 scene.GetRoot().AddChild(std::move(gltf_scene));
92 scene.GetRoot().SetLocalTransform(Matrix::MakeScale({3, 3, 3}));
93
94 Renderer::RenderCallback callback = [&](RenderTarget& render_target) {
95 Quaternion rotation({0, 1, 0}, -GetSecondsElapsed() * 0.5);
96 Vector3 start_position(-1, -1.5, -5);
97
98 // Face towards the +Z direction (+X right, +Y up).
99 auto camera = Camera::MakePerspective(
100 /* fov */ Degrees(60),
101 /* position */ rotation * start_position)
102 .LookAt(
103 /* target */ Vector3(),
104 /* up */ {0, 1, 0});
105
106 scene.Render(render_target, camera);
107 return true;
108 };
109
110 OpenPlaygroundHere(callback);
111}
112
113TEST_P(SceneTest, TwoTriangles) {
114 if (GetBackend() == PlaygroundBackend::kVulkan) {
115 GTEST_SKIP_("Temporarily disabled.");
116 }
117 auto allocator = GetContext()->GetResourceAllocator();
118
119 auto mapping =
120 flutter::testing::OpenFixtureAsMapping("two_triangles.glb.ipscene");
121 ASSERT_NE(mapping, nullptr);
122
123 std::shared_ptr<Node> gltf_scene =
124 Node::MakeFromFlatbuffer(*mapping, *allocator);
125 ASSERT_NE(gltf_scene, nullptr);
126
127 auto animation = gltf_scene->FindAnimationByName("Metronome");
128 ASSERT_NE(animation, nullptr);
129
130 AnimationClip* metronome_clip = gltf_scene->AddAnimation(animation);
131 ASSERT_NE(metronome_clip, nullptr);
132 metronome_clip->SetLoop(true);
133 metronome_clip->Play();
134
135 auto scene_context = std::make_shared<SceneContext>(GetContext());
136 auto scene = Scene(scene_context);
137 scene.GetRoot().AddChild(std::move(gltf_scene));
138
139 Renderer::RenderCallback callback = [&](RenderTarget& render_target) {
140 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
141 {
142 static Scalar playback_time_scale = 1;
143 static Scalar weight = 1;
144 static bool loop = true;
145
146 ImGui::SliderFloat("Playback time scale", &playback_time_scale, -5, 5);
147 ImGui::SliderFloat("Weight", &weight, -2, 2);
148 ImGui::Checkbox("Loop", &loop);
149 if (ImGui::Button("Play")) {
150 metronome_clip->Play();
151 }
152 if (ImGui::Button("Pause")) {
153 metronome_clip->Pause();
154 }
155 if (ImGui::Button("Stop")) {
156 metronome_clip->Stop();
157 }
158
159 metronome_clip->SetPlaybackTimeScale(playback_time_scale);
160 metronome_clip->SetWeight(weight);
161 metronome_clip->SetLoop(loop);
162 }
163
164 ImGui::End();
165 Node& node = *scene.GetRoot().GetChildren()[0];
167 Matrix::MakeRotation(Radians(0.02), {0, 1, 0, 0}));
168
169 static ImVec2 mouse_pos_prev = ImGui::GetMousePos();
170 ImVec2 mouse_pos = ImGui::GetMousePos();
171 Vector2 mouse_diff =
172 Vector2(mouse_pos.x - mouse_pos_prev.x, mouse_pos.y - mouse_pos_prev.y);
173
174 static Vector3 position(0, 1, -5);
175 static Vector3 cam_position = position;
176 auto strafe =
177 Vector3(ImGui::IsKeyDown(ImGuiKey_D) - ImGui::IsKeyDown(ImGuiKey_A),
178 ImGui::IsKeyDown(ImGuiKey_E) - ImGui::IsKeyDown(ImGuiKey_Q),
179 ImGui::IsKeyDown(ImGuiKey_W) - ImGui::IsKeyDown(ImGuiKey_S));
180 position += strafe * 0.5;
181 cam_position = cam_position.Lerp(position, 0.02);
182
183 // Face towards the +Z direction (+X right, +Y up).
184 auto camera = Camera::MakePerspective(
185 /* fov */ Degrees(60),
186 /* position */ cam_position)
187 .LookAt(
188 /* target */ cam_position + Vector3(0, 0, 1),
189 /* up */ {0, 1, 0});
190
191 scene.Render(render_target, camera);
192 return true;
193 };
194
195 OpenPlaygroundHere(callback);
196}
197
199 auto allocator = GetContext()->GetResourceAllocator();
200
201 auto mapping = flutter::testing::OpenFixtureAsMapping("dash.glb.ipscene");
202 if (!mapping) {
203 // TODO(bdero): Just skip this playground is the dash asset isn't found. I
204 // haven't checked it in because it's way too big right now,
205 // but this is still useful to keep around for debugging
206 // purposes.
207 return;
208 }
209 ASSERT_NE(mapping, nullptr);
210
211 std::shared_ptr<Node> gltf_scene =
212 Node::MakeFromFlatbuffer(*mapping, *allocator);
213 ASSERT_NE(gltf_scene, nullptr);
214
215 auto walk_anim = gltf_scene->FindAnimationByName("Walk");
216 ASSERT_NE(walk_anim, nullptr);
217
218 AnimationClip* walk_clip = gltf_scene->AddAnimation(walk_anim);
219 ASSERT_NE(walk_clip, nullptr);
220 walk_clip->SetLoop(true);
221 walk_clip->Play();
222
223 auto run_anim = gltf_scene->FindAnimationByName("Run");
224 ASSERT_NE(walk_anim, nullptr);
225
226 AnimationClip* run_clip = gltf_scene->AddAnimation(run_anim);
227 ASSERT_NE(run_clip, nullptr);
228 run_clip->SetLoop(true);
229 run_clip->Play();
230
231 auto scene_context = std::make_shared<SceneContext>(GetContext());
232 auto scene = Scene(scene_context);
233 scene.GetRoot().AddChild(std::move(gltf_scene));
234
235 Renderer::RenderCallback callback = [&](RenderTarget& render_target) {
236 ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
237 {
238 static Scalar playback_time_scale = 1;
239 static Scalar walk = 0.5;
240 static Scalar run = 0.5;
241 static bool loop = true;
242
243 ImGui::SliderFloat("Playback time scale", &playback_time_scale, -5, 5);
244 ImGui::SliderFloat("Walk weight", &walk, 0, 1);
245 ImGui::SliderFloat("Run weight", &run, 0, 1);
246 ImGui::Checkbox("Loop", &loop);
247 if (ImGui::Button("Play")) {
248 walk_clip->Play();
249 run_clip->Play();
250 }
251 if (ImGui::Button("Pause")) {
252 walk_clip->Pause();
253 run_clip->Pause();
254 }
255 if (ImGui::Button("Stop")) {
256 walk_clip->Stop();
257 run_clip->Stop();
258 }
259
260 walk_clip->SetPlaybackTimeScale(playback_time_scale);
261 walk_clip->SetWeight(walk);
262 walk_clip->SetLoop(loop);
263
264 run_clip->SetPlaybackTimeScale(playback_time_scale);
265 run_clip->SetWeight(run);
266 run_clip->SetLoop(loop);
267 }
268
269 ImGui::End();
270 Node& node = *scene.GetRoot().GetChildren()[0];
272 Matrix::MakeRotation(Radians(0.02), {0, 1, 0, 0}));
273
274 static ImVec2 mouse_pos_prev = ImGui::GetMousePos();
275 ImVec2 mouse_pos = ImGui::GetMousePos();
276 Vector2 mouse_diff =
277 Vector2(mouse_pos.x - mouse_pos_prev.x, mouse_pos.y - mouse_pos_prev.y);
278
279 static Vector3 position(0, 1, -5);
280 static Vector3 cam_position = position;
281 auto strafe =
282 Vector3(ImGui::IsKeyDown(ImGuiKey_D) - ImGui::IsKeyDown(ImGuiKey_A),
283 ImGui::IsKeyDown(ImGuiKey_E) - ImGui::IsKeyDown(ImGuiKey_Q),
284 ImGui::IsKeyDown(ImGuiKey_W) - ImGui::IsKeyDown(ImGuiKey_S));
285 position += strafe * 0.5;
286 cam_position = cam_position.Lerp(position, 0.02);
287
288 // Face towards the +Z direction (+X right, +Y up).
289 auto camera = Camera::MakePerspective(
290 /* fov */ Degrees(60),
291 /* position */ cam_position)
292 .LookAt(
293 /* target */ cam_position + Vector3(0, 0, 1),
294 /* up */ {0, 1, 0});
295
296 scene.Render(render_target, camera);
297 return true;
298 };
299
300 OpenPlaygroundHere(callback);
301}
302
303} // namespace testing
304} // namespace scene
305} // namespace impeller
std::function< bool(RenderTarget &render_target)> RenderCallback
Definition: renderer.h:23
void SetPlaybackTimeScale(Scalar playback_speed)
Sets the animation playback speed. Negative values make the clip play in reverse.
void SetWeight(Scalar weight)
static Camera MakePerspective(Radians fov_y, Vector3 position)
Definition: camera.cc:10
Camera LookAt(Vector3 target, Vector3 up=Vector3(0, -1, 0)) const
Definition: camera.cc:17
static std::shared_ptr< CuboidGeometry > MakeCuboid(Vector3 size)
Definition: geometry.cc:31
static std::unique_ptr< UnlitMaterial > MakeUnlit()
Definition: material.cc:38
void SetLocalTransform(Matrix transform)
Definition: node.cc:278
std::vector< std::shared_ptr< Node > > & GetChildren()
Definition: node.cc:325
Matrix GetLocalTransform() const
Definition: node.cc:282
static std::shared_ptr< Node > MakeFromFlatbuffer(const fml::Mapping &ipscene_mapping, Allocator &allocator)
Definition: node.cc:47
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
SK_API GrDirectContext * GetContext(const SkImage *src)
SkMesh mesh
Definition: SkRecords.h:345
std::unique_ptr< fml::Mapping > OpenFixtureAsMapping(const std::string &fixture_name)
Opens a fixture of the given file name and returns a mapping to its contents.
Definition: testing.cc:59
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
INSTANTIATE_PLAYGROUND_SUITE(SceneTest)
TEST_P(SceneTest, CuboidUnlit)
Point Vector2
Definition: point.h:326
float Scalar
Definition: scalar.h:18
constexpr float kPiOver4
Definition: constants.h:35
Definition: run.py:1
string root
Definition: scale_cpu.py:20
static constexpr Color Red()
Definition: color.h:274
static constexpr Matrix MakeTranslation(const Vector3 &t)
Definition: matrix.h:95
static constexpr Matrix MakeScale(const Vector3 &s)
Definition: matrix.h:104
static Matrix MakeRotation(Quaternion q)
Definition: matrix.h:126
constexpr Vector3 Lerp(const Vector3 &v, Scalar t) const
Definition: vector.h:178