Impeller Scene is an experimental realtime 3D renderer powered by Impeller's render layer with the following design priorities:
- Ease of use.
- Suitability for mobile.
- Common case scalability.
The aim is to create a familiar and flexible scene graph capable of building complex dynamic scenes for games and beyond.
std::shared_ptr<impeller::Context> context =
/* Create the backend-specific Impeller context */;
auto allocator = context->GetResourceAllocator();
/// Load resources.
auto dash_gltf = impeller::scene::LoadGLTF(allocator, "models/dash.glb");
auto environment_hdri =
impeller::scene::LoadHDRI(allocator, "environment/table_mountain.hdr");
/// Construct a scene.
auto scene = impeller::scene::Scene(context);
scene.Add(dash_gltf.scene);
auto& dash_player = dash_gltf.scene.CreateAnimationPlayer();
auto& walk_action = dash_player.CreateClipAction(dash_gltf.GetClip("Walk"));
walk_action.SetLoop(impeller::scene::AnimationAction::kLoopForever);
walk_action.SetWeight(0.7f);
walk_action.Seek(0.0f);
walk_action.Play();
auto& run_action = dash_player.CreateClipAction(dash_gltf.GetClip("Run"));
run_action.SetLoop(impeller::scene::AnimationAction::kLoopForever);
run_action.SetWeight(0.3f);
run_action.Play();
scene.GetRoot().AddChild(
impeller::scene::DirectionalLight(
/* color */ impeller::Color::AntiqueWhite(),
/* intensity */ 5,
/* direction */ {2, 3, 4}));
Node sphere_node;
Mesh sphere_mesh;
sphere_node.SetGlobalTransform(
Matrix::MakeRotationEuler({kPiOver4, kPiOver4, 0}));
auto sphere_geometry =
impeller::scene::Geometry::MakeSphere(allocator, /* radius */ 2);
auto material = impeller::scene::Material::MakeStandard();
material->SetAlbedo(impeller::Color::Red());
material->SetRoughness(0.4);
material->SetMetallic(0.2);
// Common properties shared by all materials.
material->SetEnvironmentMap(environment_hdri);
material->SetFlatShaded(true);
material->SetBlendConfig({
impeller::BlendOperation::kAdd, // color_op
impeller::BlendFactor::kOne, // source_color_factor
impeller::BlendFactor::kOneMinusSourceAlpha, // destination_color_factor
impeller::BlendOperation::kAdd, // alpha_op
impeller::BlendFactor::kOne, // source_alpha_factor
impeller::BlendFactor::kOneMinusSourceAlpha, // destination_alpha_factor
});
material->SetStencilConfig({
impeller::StencilOperation::kIncrementClamp, // operation
impeller::CompareFunction::kAlways, // compare
});
sphere_mesh.AddPrimitive({sphere_geometry, material});
sphere_node.SetMesh(sphere_mesh);
Node cube_node;
cube_node.SetLocalTransform(Matrix::MakeTranslation({4, 0, 0}));
Mesh cube_mesh;
auto cube_geometry = impeller::scene::Geometry::MakeCuboid(
allocator, {4, 4, 4});
cube_mesh.AddPrimitive({cube_geometry, material});
cube_node.SetMesh(cube_mesh);
sphere_node.AddChild(cube_node);
scene.GetRoot().AddChild(sphere_node);
/// Post processing.
auto dof = impeller::scene::PostProcessingEffect::MakeBokeh(
/* aperture_size */ 0.2,
/* focus_plane_distance */ 50);
scene.SetPostProcessing({dof});
/// Render the scene.
auto renderer = impeller::Renderer(context);
while(true) {
std::unique_ptr<impeller::Surface> surface = /* Wrap the window surface */;
renderer->Render(surface, [&scene](RenderTarget& render_target) {
/// Render a perspective view.
auto camera =
impeller::Camera::MakePerspective(
/* fov */ kPiOver4,
/* position */ {50, -30, 50})
.LookAt(
/* target */ impeller::Vector3::Zero,
/* up */ {0, -1, 0});
scene.Render(render_target, camera);
/// Render an overhead view on the bottom right corner of the screen.
auto size = render_target.GetRenderTargetSize();
auto minimap_camera =
impeller::Camera::MakeOrthographic(
/* view */ Rect::MakeLTRB(-100, -100, 100, 100),
/* position */ {0, -50, 0})
.LookAt(
/* target */ impeller::Vector3::Zero,
/* up */ {0, 0, 1})
.WithViewport(IRect::MakeXYWH(size.width / 4, size.height / 4,
size.height / 5, size.height / 5));
scene.Render(render_target, minimap_camera);
return true;
});
}