forked from firka/flutter
[Impeller Scene] Parse GLTF primitives (flutter/engine#38064)
This commit is contained in:
@@ -1648,13 +1648,18 @@ FILE: ../../../flutter/impeller/scene/camera.cc
|
||||
FILE: ../../../flutter/impeller/scene/camera.h
|
||||
FILE: ../../../flutter/impeller/scene/geometry.cc
|
||||
FILE: ../../../flutter/impeller/scene/geometry.h
|
||||
FILE: ../../../flutter/impeller/scene/importer/conversions.cc
|
||||
FILE: ../../../flutter/impeller/scene/importer/conversions.h
|
||||
FILE: ../../../flutter/impeller/scene/importer/importer.h
|
||||
FILE: ../../../flutter/impeller/scene/importer/importer_gltf.cc
|
||||
FILE: ../../../flutter/impeller/scene/importer/mesh.fbs
|
||||
FILE: ../../../flutter/impeller/scene/importer/importer_unittests.cc
|
||||
FILE: ../../../flutter/impeller/scene/importer/scene.fbs
|
||||
FILE: ../../../flutter/impeller/scene/importer/scenec_main.cc
|
||||
FILE: ../../../flutter/impeller/scene/importer/switches.cc
|
||||
FILE: ../../../flutter/impeller/scene/importer/switches.h
|
||||
FILE: ../../../flutter/impeller/scene/importer/types.h
|
||||
FILE: ../../../flutter/impeller/scene/importer/vertices_builder.cc
|
||||
FILE: ../../../flutter/impeller/scene/importer/vertices_builder.h
|
||||
FILE: ../../../flutter/impeller/scene/material.cc
|
||||
FILE: ../../../flutter/impeller/scene/material.h
|
||||
FILE: ../../../flutter/impeller/scene/scene.cc
|
||||
|
||||
@@ -74,6 +74,7 @@ impeller_component("impeller_unittests") {
|
||||
"compiler:compiler_unittests",
|
||||
"geometry:geometry_unittests",
|
||||
"runtime_stage:runtime_stage_unittests",
|
||||
"scene/importer:importer_unittests",
|
||||
"tessellator:tessellator_unittests",
|
||||
]
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@ test_fixtures("file_fixtures") {
|
||||
"blue_noise.png",
|
||||
"boston.jpg",
|
||||
"embarcadero.jpg",
|
||||
"flutter_logo.glb",
|
||||
"kalimba.jpg",
|
||||
"multiple_stages.hlsl",
|
||||
"resources_limit.vert",
|
||||
|
||||
@@ -12,22 +12,26 @@ config("runtime_stage_config") {
|
||||
}
|
||||
|
||||
flatbuffers("importer_flatbuffers") {
|
||||
flatbuffers = [ "mesh.fbs" ]
|
||||
flatbuffers = [ "scene.fbs" ]
|
||||
public_configs = [ ":runtime_stage_config" ]
|
||||
public_deps = [ "//third_party/flatbuffers" ]
|
||||
}
|
||||
|
||||
impeller_component("scenec_lib") {
|
||||
impeller_component("importer_lib") {
|
||||
# Current versions of libcxx have deprecated some of the UTF-16 string
|
||||
# conversion APIs.
|
||||
defines = [ "_LIBCPP_DISABLE_DEPRECATION_WARNINGS" ]
|
||||
|
||||
sources = [
|
||||
"conversions.cc",
|
||||
"conversions.h",
|
||||
"importer.h",
|
||||
"importer_gltf.cc",
|
||||
"switches.cc",
|
||||
"switches.h",
|
||||
"types.h",
|
||||
"vertices_builder.cc",
|
||||
"vertices_builder.h",
|
||||
]
|
||||
|
||||
public_deps = [
|
||||
@@ -39,8 +43,7 @@ impeller_component("scenec_lib") {
|
||||
|
||||
# All third_party deps must be reflected below in the scenec_license
|
||||
# target.
|
||||
# TODO(bdero): Fix tinygltf compilation warnings.
|
||||
#"//third_party/tinygltf",
|
||||
"//third_party/tinygltf",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -85,9 +88,24 @@ impeller_component("scenec") {
|
||||
|
||||
sources = [ "scenec_main.cc" ]
|
||||
|
||||
deps = [ ":scenec_lib" ]
|
||||
deps = [ ":importer_lib" ]
|
||||
|
||||
metadata = {
|
||||
entitlement_file_path = [ "scenec" ]
|
||||
}
|
||||
}
|
||||
|
||||
impeller_component("importer_unittests") {
|
||||
testonly = true
|
||||
|
||||
output_name = "scenec_unittests"
|
||||
|
||||
sources = [ "importer_unittests.cc" ]
|
||||
|
||||
deps = [
|
||||
":importer_lib",
|
||||
"../../fixtures",
|
||||
"../../geometry:geometry_unittests",
|
||||
"//flutter/testing:testing_lib",
|
||||
]
|
||||
}
|
||||
|
||||
80
engine/src/flutter/impeller/scene/importer/conversions.cc
Normal file
80
engine/src/flutter/impeller/scene/importer/conversions.cc
Normal file
@@ -0,0 +1,80 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "impeller/scene/importer/conversions.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "impeller/scene/importer/scene_flatbuffers.h"
|
||||
|
||||
namespace impeller {
|
||||
namespace scene {
|
||||
namespace importer {
|
||||
|
||||
Matrix ToMatrix(const std::vector<double>& m) {
|
||||
return Matrix(m[0], m[1], m[2], m[3], //
|
||||
m[4], m[5], m[6], m[7], //
|
||||
m[8], m[9], m[10], m[11], //
|
||||
m[12], m[13], m[14], m[15]);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Flatbuffers -> Impeller
|
||||
///
|
||||
|
||||
Matrix ToMatrix(const fb::Matrix& m) {
|
||||
auto& a = *m.m();
|
||||
return Matrix(a[0], a[1], a[2], a[3], //
|
||||
a[4], a[5], a[6], a[7], //
|
||||
a[8], a[9], a[10], a[11], //
|
||||
a[12], a[13], a[14], a[15]);
|
||||
}
|
||||
|
||||
Vector2 ToVector2(const fb::Vec2& v) {
|
||||
return Vector2(v.x(), v.y());
|
||||
}
|
||||
|
||||
Vector3 ToVector3(const fb::Vec3& v) {
|
||||
return Vector3(v.x(), v.y(), v.z());
|
||||
}
|
||||
|
||||
Vector4 ToVector4(const fb::Vec4& v) {
|
||||
return Vector4(v.x(), v.y(), v.z(), v.w());
|
||||
}
|
||||
|
||||
Color ToColor(const fb::Color& c) {
|
||||
return Color(c.r(), c.g(), c.b(), c.a());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Impeller -> Flatbuffers
|
||||
///
|
||||
|
||||
std::unique_ptr<fb::Matrix> ToFBMatrix(const Matrix& m) {
|
||||
auto array = std::array<Scalar, 16>{m.m[0], m.m[1], m.m[2], m.m[3], //
|
||||
m.m[4], m.m[5], m.m[6], m.m[7], //
|
||||
m.m[8], m.m[9], m.m[10], m.m[11], //
|
||||
m.m[12], m.m[13], m.m[14], m.m[15]};
|
||||
return std::make_unique<fb::Matrix>(array);
|
||||
}
|
||||
|
||||
fb::Vec2 ToFBVec2(const Vector2 v) {
|
||||
return fb::Vec2(v.x, v.y);
|
||||
}
|
||||
|
||||
fb::Vec3 ToFBVec3(const Vector3 v) {
|
||||
return fb::Vec3(v.x, v.y, v.z);
|
||||
}
|
||||
|
||||
fb::Vec4 ToFBVec4(const Vector4 v) {
|
||||
return fb::Vec4(v.x, v.y, v.z, v.w);
|
||||
}
|
||||
|
||||
fb::Color ToFBColor(const Color c) {
|
||||
return fb::Color(c.red, c.green, c.blue, c.alpha);
|
||||
}
|
||||
|
||||
} // namespace importer
|
||||
} // namespace scene
|
||||
} // namespace impeller
|
||||
49
engine/src/flutter/impeller/scene/importer/conversions.h
Normal file
49
engine/src/flutter/impeller/scene/importer/conversions.h
Normal file
@@ -0,0 +1,49 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <map>
|
||||
|
||||
#include "impeller/geometry/matrix.h"
|
||||
#include "impeller/scene/importer/scene_flatbuffers.h"
|
||||
|
||||
namespace impeller {
|
||||
namespace scene {
|
||||
namespace importer {
|
||||
|
||||
Matrix ToMatrix(const std::vector<double>& m);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Flatbuffers -> Impeller
|
||||
///
|
||||
|
||||
Matrix ToMatrix(const fb::Matrix& m);
|
||||
|
||||
Vector2 ToVector2(const fb::Vec2& c);
|
||||
|
||||
Vector3 ToVector3(const fb::Vec3& c);
|
||||
|
||||
Vector4 ToVector4(const fb::Vec4& c);
|
||||
|
||||
Color ToColor(const fb::Color& c);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Impeller -> Flatbuffers
|
||||
///
|
||||
|
||||
std::unique_ptr<fb::Matrix> ToFBMatrix(const Matrix& m);
|
||||
|
||||
fb::Vec2 ToFBVec2(const Vector2 v);
|
||||
|
||||
fb::Vec3 ToFBVec3(const Vector3 v);
|
||||
|
||||
fb::Vec4 ToFBVec4(const Vector4 v);
|
||||
|
||||
fb::Color ToFBColor(const Color c);
|
||||
|
||||
} // namespace importer
|
||||
} // namespace scene
|
||||
} // namespace impeller
|
||||
@@ -2,17 +2,19 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
|
||||
#include "flutter/fml/mapping.h"
|
||||
#include "impeller/scene/importer/mesh_flatbuffers.h"
|
||||
#include "impeller/scene/importer/scene_flatbuffers.h"
|
||||
|
||||
namespace impeller {
|
||||
namespace scene {
|
||||
namespace importer {
|
||||
|
||||
bool ParseGLTF(const fml::Mapping& source_mapping, fb::MeshT& out_mesh);
|
||||
bool ParseGLTF(const fml::Mapping& source_mapping, fb::SceneT& out_scene);
|
||||
|
||||
}
|
||||
} // namespace scene
|
||||
|
||||
@@ -2,20 +2,211 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
|
||||
#include "impeller/scene/importer/importer.h"
|
||||
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "flutter/fml/mapping.h"
|
||||
#include "impeller/geometry/matrix.h"
|
||||
#include "impeller/scene/importer/conversions.h"
|
||||
#include "impeller/scene/importer/scene_flatbuffers.h"
|
||||
#include "impeller/scene/importer/vertices_builder.h"
|
||||
#include "third_party/tinygltf/tiny_gltf.h"
|
||||
|
||||
namespace impeller {
|
||||
namespace scene {
|
||||
namespace importer {
|
||||
|
||||
bool ParseGLTF(const fml::Mapping& source_mapping, fb::MeshT& out_mesh) {
|
||||
// TODO(bdero): Parse source_mapping and populare out_mesh with just the first
|
||||
// mesh in the GLTF.
|
||||
static const std::map<std::string, VerticesBuilder::Attribute> kAttributes = {
|
||||
{"POSITION", VerticesBuilder::Attribute::kPosition},
|
||||
{"NORMAL", VerticesBuilder::Attribute::kNormal},
|
||||
{"TANGENT", VerticesBuilder::Attribute::kTangent},
|
||||
{"TEXCOORD_0", VerticesBuilder::Attribute::kTextureCoords},
|
||||
{"COLOR_0", VerticesBuilder::Attribute::kColor},
|
||||
};
|
||||
|
||||
static bool WithinRange(int index, size_t size) {
|
||||
return index >= 0 && static_cast<size_t>(index) < size;
|
||||
}
|
||||
|
||||
static bool ProcessStaticMesh(const tinygltf::Model& gltf,
|
||||
const tinygltf::Primitive& primitive,
|
||||
fb::StaticMeshT& static_mesh) {
|
||||
//---------------------------------------------------------------------------
|
||||
/// Vertices.
|
||||
///
|
||||
|
||||
{
|
||||
VerticesBuilder builder;
|
||||
|
||||
for (const auto& attribute : primitive.attributes) {
|
||||
auto attribute_type = kAttributes.find(attribute.first);
|
||||
if (attribute_type == kAttributes.end()) {
|
||||
std::cerr << "Vertex attribute \"" << attribute.first
|
||||
<< "\" not supported." << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto accessor = gltf.accessors[attribute.second];
|
||||
const auto view = gltf.bufferViews[accessor.bufferView];
|
||||
|
||||
const auto buffer = gltf.buffers[view.buffer];
|
||||
const unsigned char* source_start = &buffer.data[view.byteOffset];
|
||||
|
||||
VerticesBuilder::ComponentType type;
|
||||
switch (accessor.componentType) {
|
||||
case TINYGLTF_COMPONENT_TYPE_BYTE:
|
||||
type = VerticesBuilder::ComponentType::kSignedByte;
|
||||
break;
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE:
|
||||
type = VerticesBuilder::ComponentType::kUnsignedByte;
|
||||
break;
|
||||
case TINYGLTF_COMPONENT_TYPE_SHORT:
|
||||
type = VerticesBuilder::ComponentType::kSignedShort;
|
||||
break;
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT:
|
||||
type = VerticesBuilder::ComponentType::kUnsignedShort;
|
||||
break;
|
||||
case TINYGLTF_COMPONENT_TYPE_INT:
|
||||
type = VerticesBuilder::ComponentType::kSignedInt;
|
||||
break;
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT:
|
||||
type = VerticesBuilder::ComponentType::kUnsignedInt;
|
||||
break;
|
||||
case TINYGLTF_COMPONENT_TYPE_FLOAT:
|
||||
type = VerticesBuilder::ComponentType::kFloat;
|
||||
break;
|
||||
default:
|
||||
std::cerr << "Skipping attribute \"" << attribute.first
|
||||
<< "\" due to invalid component type." << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
builder.SetAttributeFromBuffer(attribute_type->second, // attribute
|
||||
type, // component_type
|
||||
source_start, // buffer_start
|
||||
accessor.ByteStride(view), // stride_bytes
|
||||
accessor.count); // count
|
||||
}
|
||||
|
||||
builder.WriteFBVertices(static_mesh.vertices);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
/// Indices.
|
||||
///
|
||||
|
||||
if (!WithinRange(primitive.indices, gltf.accessors.size())) {
|
||||
std::cerr << "Mesh primitive has no index buffer. Skipping." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto index_accessor = gltf.accessors[primitive.indices];
|
||||
auto index_view = gltf.bufferViews[index_accessor.bufferView];
|
||||
static_mesh.indices.resize(index_accessor.count);
|
||||
const auto* index_buffer =
|
||||
&gltf.buffers[index_view.buffer].data[index_view.byteOffset];
|
||||
std::memcpy(static_mesh.indices.data(), index_buffer, index_view.byteLength);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ProcessNode(const tinygltf::Model& gltf,
|
||||
const tinygltf::Node& in_node,
|
||||
fb::NodeT& out_node) {
|
||||
//---------------------------------------------------------------------------
|
||||
/// Transform.
|
||||
///
|
||||
|
||||
Matrix transform;
|
||||
if (in_node.translation.size() == 3) {
|
||||
transform = transform * Matrix::MakeTranslation(
|
||||
{static_cast<Scalar>(in_node.translation[0]),
|
||||
static_cast<Scalar>(in_node.translation[0]),
|
||||
static_cast<Scalar>(in_node.translation[0])});
|
||||
}
|
||||
if (in_node.rotation.size() == 4) {
|
||||
transform = transform * Matrix::MakeRotation(Quaternion(
|
||||
in_node.rotation[0], in_node.rotation[1],
|
||||
in_node.rotation[2], in_node.rotation[3]));
|
||||
}
|
||||
if (in_node.scale.size() == 3) {
|
||||
transform =
|
||||
transform * Matrix::MakeScale({static_cast<Scalar>(in_node.scale[0]),
|
||||
static_cast<Scalar>(in_node.scale[1]),
|
||||
static_cast<Scalar>(in_node.scale[2])});
|
||||
}
|
||||
if (in_node.matrix.size() == 16) {
|
||||
if (!transform.IsIdentity()) {
|
||||
std::cerr << "The `matrix` attribute of node (name: " << in_node.name
|
||||
<< ") is set in addition to one or more of the "
|
||||
"`translation/rotation/scale` attributes. Using only the "
|
||||
"`matrix` "
|
||||
"attribute.";
|
||||
}
|
||||
transform = ToMatrix(in_node.matrix);
|
||||
}
|
||||
out_node.transform = ToFBMatrix(transform);
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
/// Static meshes.
|
||||
///
|
||||
|
||||
if (WithinRange(in_node.mesh, gltf.meshes.size())) {
|
||||
auto& mesh = gltf.meshes[in_node.mesh];
|
||||
for (const auto& primitive : mesh.primitives) {
|
||||
auto static_mesh = std::make_unique<fb::StaticMeshT>();
|
||||
if (!ProcessStaticMesh(gltf, primitive, *static_mesh)) {
|
||||
continue;
|
||||
}
|
||||
out_node.meshes.push_back(std::move(static_mesh));
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
/// Children.
|
||||
///
|
||||
|
||||
for (size_t node_i = 0; node_i < out_node.children.size(); node_i++) {
|
||||
auto child = std::make_unique<fb::NodeT>();
|
||||
ProcessNode(gltf, gltf.nodes[in_node.children[node_i]], *child);
|
||||
out_node.children.push_back(std::move(child));
|
||||
}
|
||||
}
|
||||
|
||||
bool ParseGLTF(const fml::Mapping& source_mapping, fb::SceneT& out_scene) {
|
||||
tinygltf::Model gltf;
|
||||
|
||||
{
|
||||
tinygltf::TinyGLTF loader;
|
||||
std::string error;
|
||||
std::string warning;
|
||||
bool success = loader.LoadBinaryFromMemory(&gltf, &error, &warning,
|
||||
source_mapping.GetMapping(),
|
||||
source_mapping.GetSize());
|
||||
if (!warning.empty()) {
|
||||
std::cerr << "Warning while loading GLTF: " << warning << std::endl;
|
||||
}
|
||||
if (!error.empty()) {
|
||||
std::cerr << "Error while loading GLTF: " << error << std::endl;
|
||||
}
|
||||
if (!success) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const tinygltf::Scene& scene = gltf.scenes[gltf.defaultScene];
|
||||
for (size_t node_i = 0; node_i < scene.nodes.size(); node_i++) {
|
||||
auto node = std::make_unique<fb::NodeT>();
|
||||
ProcessNode(gltf, gltf.nodes[scene.nodes[node_i]], *node);
|
||||
out_scene.children.push_back(std::move(node));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "flutter/testing/testing.h"
|
||||
#include "impeller/geometry/geometry_unittests.h"
|
||||
#include "impeller/geometry/matrix.h"
|
||||
#include "impeller/scene/importer/conversions.h"
|
||||
#include "impeller/scene/importer/importer.h"
|
||||
#include "impeller/scene/importer/scene_flatbuffers.h"
|
||||
|
||||
namespace impeller {
|
||||
namespace scene {
|
||||
namespace importer {
|
||||
namespace testing {
|
||||
|
||||
TEST(ImporterTest, CanParseGLTF) {
|
||||
auto mapping = flutter::testing::OpenFixtureAsMapping("flutter_logo.glb");
|
||||
|
||||
fb::SceneT scene;
|
||||
ASSERT_TRUE(ParseGLTF(*mapping, scene));
|
||||
|
||||
ASSERT_EQ(scene.children.size(), 1u);
|
||||
auto& node = *scene.children[0];
|
||||
|
||||
Matrix node_transform = ToMatrix(*node.transform);
|
||||
ASSERT_MATRIX_NEAR(node_transform, Matrix());
|
||||
|
||||
ASSERT_EQ(node.meshes.size(), 1u);
|
||||
auto& mesh = *node.meshes[0];
|
||||
ASSERT_EQ(mesh.indices.size(), 918u);
|
||||
|
||||
ASSERT_EQ(mesh.vertices.size(), 260u);
|
||||
auto& vertex = mesh.vertices[0];
|
||||
|
||||
Vector3 position = ToVector3(vertex.position());
|
||||
ASSERT_VECTOR3_NEAR(position, Vector3(-0.0100185, -0.522907, 0.133178));
|
||||
|
||||
Vector3 normal = ToVector3(vertex.normal());
|
||||
ASSERT_VECTOR3_NEAR(normal, Vector3(0.556997, -0.810833, 0.179733));
|
||||
|
||||
Vector4 tangent = ToVector4(vertex.tangent());
|
||||
ASSERT_VECTOR4_NEAR(tangent, Vector4(0.155901, -0.110485, -0.981574, 1));
|
||||
|
||||
Vector2 texture_coords = ToVector2(vertex.texture_coords());
|
||||
ASSERT_POINT_NEAR(texture_coords, Vector2(0.727937, 0.713817));
|
||||
|
||||
Color color = ToColor(vertex.color());
|
||||
ASSERT_COLOR_NEAR(color, Color(0.0221714, 0.467781, 0.921584, 1));
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace importer
|
||||
} // namespace scene
|
||||
} // namespace impeller
|
||||
@@ -1,37 +0,0 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
namespace impeller.fb;
|
||||
|
||||
struct Vec2 {
|
||||
x: float;
|
||||
y: float;
|
||||
}
|
||||
|
||||
struct Vec3 {
|
||||
x: float;
|
||||
y: float;
|
||||
z: float;
|
||||
}
|
||||
|
||||
struct Color {
|
||||
r: float;
|
||||
g: float;
|
||||
b: float;
|
||||
}
|
||||
|
||||
struct Vertex {
|
||||
position: Vec3;
|
||||
normal: Vec3;
|
||||
tangent: Vec3;
|
||||
texture_coords: Vec2;
|
||||
}
|
||||
|
||||
table Mesh {
|
||||
vertices: [Vertex];
|
||||
indices: [uint16];
|
||||
}
|
||||
|
||||
root_type Mesh;
|
||||
file_identifier "IPME";
|
||||
72
engine/src/flutter/impeller/scene/importer/scene.fbs
Normal file
72
engine/src/flutter/impeller/scene/importer/scene.fbs
Normal file
@@ -0,0 +1,72 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
namespace impeller.fb;
|
||||
|
||||
struct Vec2 {
|
||||
x: float;
|
||||
y: float;
|
||||
}
|
||||
|
||||
struct Vec3 {
|
||||
x: float;
|
||||
y: float;
|
||||
z: float;
|
||||
}
|
||||
|
||||
struct Vec4 {
|
||||
x: float;
|
||||
y: float;
|
||||
z: float;
|
||||
w: float;
|
||||
}
|
||||
|
||||
struct Color {
|
||||
r: float;
|
||||
g: float;
|
||||
b: float;
|
||||
a: float;
|
||||
}
|
||||
|
||||
struct Matrix {
|
||||
m: [float:16];
|
||||
}
|
||||
|
||||
struct Vertex {
|
||||
position: Vec3;
|
||||
normal: Vec3;
|
||||
tangent: Vec4; // The 4th component determines the handedness of the tangent.
|
||||
texture_coords: Vec2;
|
||||
color: Color;
|
||||
}
|
||||
|
||||
table Texture {
|
||||
// TODO(bdero): Allow optional image data embedding.
|
||||
uri: string;
|
||||
}
|
||||
|
||||
table Material {
|
||||
base_color_factor: Color;
|
||||
base_color_texture: Texture;
|
||||
// TODO(bdero): PBR textures.
|
||||
}
|
||||
|
||||
table StaticMesh {
|
||||
vertices: [Vertex];
|
||||
indices: [uint32];
|
||||
material: Material;
|
||||
}
|
||||
|
||||
table Node {
|
||||
children: [Node];
|
||||
transform: Matrix;
|
||||
meshes: [StaticMesh];
|
||||
}
|
||||
|
||||
table Scene {
|
||||
children: [Node];
|
||||
}
|
||||
|
||||
root_type Scene;
|
||||
file_identifier "IPSC";
|
||||
@@ -58,11 +58,11 @@ bool Main(const fml::CommandLine& command_line) {
|
||||
return false;
|
||||
}
|
||||
|
||||
fb::MeshT mesh;
|
||||
fb::SceneT scene;
|
||||
bool success = false;
|
||||
switch (switches.input_type) {
|
||||
case SourceType::kGLTF:
|
||||
success = ParseGLTF(*source_file_mapping, mesh);
|
||||
success = ParseGLTF(*source_file_mapping, scene);
|
||||
break;
|
||||
case SourceType::kUnknown:
|
||||
std::cerr << "Unknown input type." << std::endl;
|
||||
@@ -74,7 +74,7 @@ bool Main(const fml::CommandLine& command_line) {
|
||||
}
|
||||
|
||||
flatbuffers::FlatBufferBuilder builder;
|
||||
builder.Finish(fb::Mesh::Pack(builder, &mesh));
|
||||
builder.Finish(fb::Scene::Pack(builder, &scene));
|
||||
|
||||
auto output_file_name = std::filesystem::absolute(
|
||||
std::filesystem::current_path() / switches.output_file_name);
|
||||
|
||||
115
engine/src/flutter/impeller/scene/importer/vertices_builder.cc
Normal file
115
engine/src/flutter/impeller/scene/importer/vertices_builder.cc
Normal file
@@ -0,0 +1,115 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "impeller/scene/importer/vertices_builder.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
#include "impeller/scene/importer/conversions.h"
|
||||
#include "impeller/scene/importer/scene_flatbuffers.h"
|
||||
|
||||
namespace impeller {
|
||||
namespace scene {
|
||||
namespace importer {
|
||||
|
||||
VerticesBuilder::VerticesBuilder() = default;
|
||||
|
||||
std::map<VerticesBuilder::Attribute, VerticesBuilder::AttributeProperties>
|
||||
VerticesBuilder::kAttributes = {
|
||||
{VerticesBuilder::Attribute::kPosition,
|
||||
{.offset_bytes = offsetof(Vertex, position),
|
||||
.size_bytes = sizeof(Vertex::position),
|
||||
.component_count = 3}},
|
||||
{VerticesBuilder::Attribute::kNormal,
|
||||
{.offset_bytes = offsetof(Vertex, normal),
|
||||
.size_bytes = sizeof(Vertex::normal),
|
||||
.component_count = 3}},
|
||||
{VerticesBuilder::Attribute::kTangent,
|
||||
{.offset_bytes = offsetof(Vertex, tangent),
|
||||
.size_bytes = sizeof(Vertex::tangent),
|
||||
.component_count = 4}},
|
||||
{VerticesBuilder::Attribute::kTextureCoords,
|
||||
{.offset_bytes = offsetof(Vertex, texture_coords),
|
||||
.size_bytes = sizeof(Vertex::texture_coords),
|
||||
.component_count = 2}},
|
||||
{VerticesBuilder::Attribute::kColor,
|
||||
{.offset_bytes = offsetof(Vertex, color),
|
||||
.size_bytes = sizeof(Vertex::color),
|
||||
.component_count = 4}}};
|
||||
|
||||
void VerticesBuilder::WriteFBVertices(std::vector<fb::Vertex>& vertices) const {
|
||||
vertices.resize(0);
|
||||
for (auto& v : vertices_) {
|
||||
vertices.push_back(fb::Vertex(
|
||||
ToFBVec3(v.position), ToFBVec3(v.normal), ToFBVec4(v.tangent),
|
||||
ToFBVec2(v.texture_coords), ToFBColor(v.color)));
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Reads a contiguous sequence of numeric components from `source` and
|
||||
/// writes them to `destination` as 32bit floats. Signed SourceTypes
|
||||
/// convert to a range of -1 to 1, and unsigned SourceTypes convert to a
|
||||
/// range of 0 to 1.
|
||||
template <typename SourceType>
|
||||
static void WriteComponentsAsScalars(void* destination,
|
||||
const void* source,
|
||||
size_t component_count) {
|
||||
constexpr SourceType divisor = std::is_integral_v<SourceType>
|
||||
? std::numeric_limits<SourceType>::max()
|
||||
: 1;
|
||||
for (size_t i = 0; i < component_count; i++) {
|
||||
const SourceType* s = reinterpret_cast<const SourceType*>(source) + i;
|
||||
Scalar v = static_cast<Scalar>(*s) / static_cast<Scalar>(divisor);
|
||||
Scalar* dest = reinterpret_cast<Scalar*>(destination) + i;
|
||||
*dest = v;
|
||||
}
|
||||
}
|
||||
|
||||
static std::map<
|
||||
VerticesBuilder::ComponentType,
|
||||
std::function<
|
||||
void(void* destination, const void* source, size_t component_count)>>
|
||||
kAttributeWriters = {
|
||||
{VerticesBuilder::ComponentType::kSignedByte,
|
||||
WriteComponentsAsScalars<int8_t>},
|
||||
{VerticesBuilder::ComponentType::kUnsignedByte,
|
||||
WriteComponentsAsScalars<uint8_t>},
|
||||
{VerticesBuilder::ComponentType::kSignedShort,
|
||||
WriteComponentsAsScalars<int16_t>},
|
||||
{VerticesBuilder::ComponentType::kUnsignedShort,
|
||||
WriteComponentsAsScalars<uint16_t>},
|
||||
{VerticesBuilder::ComponentType::kSignedInt,
|
||||
WriteComponentsAsScalars<int32_t>},
|
||||
{VerticesBuilder::ComponentType::kUnsignedInt,
|
||||
WriteComponentsAsScalars<uint32_t>},
|
||||
{VerticesBuilder::ComponentType::kFloat,
|
||||
WriteComponentsAsScalars<float>},
|
||||
};
|
||||
|
||||
void VerticesBuilder::SetAttributeFromBuffer(Attribute attribute,
|
||||
ComponentType component_type,
|
||||
const void* buffer_start,
|
||||
size_t stride_bytes,
|
||||
size_t count) {
|
||||
if (count > vertices_.size()) {
|
||||
vertices_.resize(count, Vertex());
|
||||
}
|
||||
|
||||
const auto& properties = kAttributes[attribute];
|
||||
const auto& writer = kAttributeWriters[component_type];
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
const char* source =
|
||||
reinterpret_cast<const char*>(buffer_start) + stride_bytes * i;
|
||||
char* destination =
|
||||
reinterpret_cast<char*>(&vertices_.data()[i]) + properties.offset_bytes;
|
||||
|
||||
writer(destination, source, properties.component_count);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace importer
|
||||
} // namespace scene
|
||||
} // namespace impeller
|
||||
@@ -0,0 +1,74 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <map>
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "impeller/geometry/matrix.h"
|
||||
#include "impeller/scene/importer/scene_flatbuffers.h"
|
||||
|
||||
namespace impeller {
|
||||
namespace scene {
|
||||
namespace importer {
|
||||
|
||||
class VerticesBuilder {
|
||||
public:
|
||||
enum class Attribute {
|
||||
kPosition,
|
||||
kNormal,
|
||||
kTangent,
|
||||
kTextureCoords,
|
||||
kColor,
|
||||
};
|
||||
|
||||
enum class ComponentType {
|
||||
kSignedByte = 5120,
|
||||
kUnsignedByte,
|
||||
kSignedShort,
|
||||
kUnsignedShort,
|
||||
kSignedInt,
|
||||
kUnsignedInt,
|
||||
kFloat,
|
||||
};
|
||||
|
||||
VerticesBuilder();
|
||||
|
||||
void WriteFBVertices(std::vector<fb::Vertex>& vertices) const;
|
||||
|
||||
void SetAttributeFromBuffer(Attribute attribute,
|
||||
ComponentType component_type,
|
||||
const void* buffer_start,
|
||||
size_t stride_bytes,
|
||||
size_t count);
|
||||
|
||||
private:
|
||||
struct AttributeProperties {
|
||||
size_t offset_bytes;
|
||||
size_t size_bytes;
|
||||
size_t component_count;
|
||||
};
|
||||
|
||||
static std::map<VerticesBuilder::Attribute,
|
||||
VerticesBuilder::AttributeProperties>
|
||||
kAttributes;
|
||||
|
||||
struct Vertex {
|
||||
Vector3 position;
|
||||
Vector3 normal;
|
||||
Vector4 tangent;
|
||||
Vector2 texture_coords;
|
||||
Color color = Color::White();
|
||||
};
|
||||
|
||||
std::vector<Vertex> vertices_;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(VerticesBuilder);
|
||||
};
|
||||
|
||||
} // namespace importer
|
||||
} // namespace scene
|
||||
} // namespace impeller
|
||||
Reference in New Issue
Block a user