Skip to content

Commit

Permalink
SubMeshにGameMaterial(int)を追加 (#211)
Browse files Browse the repository at this point in the history
* SubMeshにGameMaterialIDを追加、そのgetter,setterを追加

* gameMaterialのコピー

* SubMesh比較の改善

* CityObjectIndexをHashSetで利用可能にするためのメソッド実装
  • Loading branch information
linoal authored Nov 29, 2023
1 parent e900a9b commit ae8c2e6
Show file tree
Hide file tree
Showing 13 changed files with 136 additions and 27 deletions.
2 changes: 1 addition & 1 deletion include/plateau/polygon_mesh/mesh.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ namespace plateau::polygonMesh {
* 代わりに extendLastSubMesh を実行します。
* なぜなら、同じテクスチャであればサブメッシュを分けるのは無意味で描画負荷を増やすだけと思われるためです。
*/
void addSubMesh(const std::string& texture_path, std::shared_ptr<const citygml::Material> material, size_t sub_mesh_start_index, size_t sub_mesh_end_index);
void addSubMesh(const std::string& texture_path, std::shared_ptr<const citygml::Material> material, size_t sub_mesh_start_index, size_t sub_mesh_end_index, int game_material_id);

/**
* 直前の SubMesh の範囲を拡大し、範囲の終わりがindicesリストの最後を指すようにします。
Expand Down
22 changes: 21 additions & 1 deletion include/plateau/polygon_mesh/sub_mesh.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,21 @@ namespace plateau::polygonMesh {
*/
class LIBPLATEAU_EXPORT SubMesh {
public:
/**
* テクスチャパスとcitygml::MaterialからSubMeshを初期化します。
*/
SubMesh(size_t start_index, size_t end_index, const std::string& texture_path, std::shared_ptr<const citygml::Material> material);

/**
* GamemMaterialIDも含めてSubMeshを初期化します。
*/
SubMesh(size_t start_index, size_t end_index, const std::string& texture_path, std::shared_ptr<const citygml::Material> material, int game_material_id);

/**
* 引数で与えられた SubMesh の vector に SubMesh を追加します。
*/
static void addSubMesh(size_t start_index, size_t end_index,
const std::string& texture_path, std::shared_ptr<const citygml::Material> material, std::vector<SubMesh>& vector);
const std::string& texture_path, std::shared_ptr<const citygml::Material> material, int game_material_id, std::vector<SubMesh>& vector);

size_t getStartIndex() const;
size_t getEndIndex() const;
Expand All @@ -34,6 +42,10 @@ namespace plateau::polygonMesh {

void setStartIndex(size_t start_index);
void setEndIndex(size_t end_index);
void setGameMaterialID(int id);
int getGameMaterialID() const;

bool isSameAs(const SubMesh& other) const;

bool operator==(const SubMesh& other) const;

Expand All @@ -49,5 +61,13 @@ namespace plateau::polygonMesh {
size_t end_index_;
std::string texture_path_;
std::shared_ptr<const citygml::Material> material_;

/**
* ゲームエンジンのマテリアルを利用したい場合に、上の texture_path_ や material_ の代わりに利用するマテリアルIDです。
* 特に分割結合時にゲームエンジンのマテリアルを維持するために利用します。
* IDが具体的にどのマテリアルを指すかはゲームエンジンの責任で決めます。
* 初期値は-1です。
*/
int game_material_id_;
};
}
2 changes: 1 addition & 1 deletion src/c_wrapper/mesh_c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ extern "C" {
int sub_mesh_end_index
) {
API_TRY{
mesh->addSubMesh(texture_path, nullptr, sub_mesh_start_index, sub_mesh_end_index);
mesh->addSubMesh(texture_path, nullptr, sub_mesh_start_index, sub_mesh_end_index, -1);
return APIResult::Success;
} API_CATCH
return APIResult::ErrorUnknown;
Expand Down
10 changes: 10 additions & 0 deletions src/c_wrapper/sub_mesh_c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@ extern "C"{
citygml::Material,
handle->getMaterial().get())

DLL_2_ARG_FUNC(plateau_sub_mesh_set_game_material_id,
SubMesh* sub_mesh,
int game_material_id,
sub_mesh->setGameMaterialID(game_material_id))

DLL_VALUE_FUNC(plateau_sub_mesh_get_game_material_id,
SubMesh,
int,
handle->getGameMaterialID())

LIBPLATEAU_C_EXPORT APIResult LIBPLATEAU_C_API plateau_create_sub_mesh(
SubMesh** out_sub_mesh_ptr,
const int start_index,
Expand Down
27 changes: 10 additions & 17 deletions src/polygon_mesh/mesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,32 +143,25 @@ namespace plateau::polygonMesh {
}
}

void Mesh::addSubMesh(const std::string& texture_path, std::shared_ptr<const citygml::Material> material, size_t sub_mesh_start_index, size_t sub_mesh_end_index) {
void Mesh::addSubMesh(const std::string& texture_path, std::shared_ptr<const citygml::Material> material, size_t sub_mesh_start_index, size_t sub_mesh_end_index, int game_material_id) {
// テクスチャが異なる場合は追加します。
// TODO テクスチャありのポリゴン と なしのポリゴン が交互にマージされることで、テクスチャなしのサブメッシュが大量に生成されるので描画負荷に改善の余地ありです。
// テクスチャなしのサブメッシュは1つにまとめたいところです。テクスチャなしのポリゴンを連続してマージすることで1つにまとまるはずです。

// 前と同じテクスチャかどうか判定します
bool is_different_tex;
// 前と同じマテリアルかどうか判定します
bool are_materials_same;
if (sub_meshes_.empty()) {
is_different_tex = true;
are_materials_same = false;
} else {
auto& last_texture_path = sub_meshes_.rbegin()->getTexturePath();
is_different_tex = texture_path != last_texture_path;

// 前と同じマテリアルかどうか判定します。
if (!is_different_tex) {
auto last_material = sub_meshes_.rbegin()->getMaterial();
if (material != nullptr && last_material != nullptr)
is_different_tex = material->getId() != last_material->getId();
else if ((material == nullptr && last_material != nullptr) || (material != nullptr && last_material == nullptr))
is_different_tex = true;
}
const auto& last_sub_mesh = sub_meshes_.rbegin();
are_materials_same =
SubMesh(sub_mesh_start_index, sub_mesh_end_index, texture_path, material, game_material_id)
.isSameAs(*last_sub_mesh);
}

if (is_different_tex) {
if (!are_materials_same) {
// テクスチャが違うなら、サブメッシュを追加します。
SubMesh::addSubMesh(sub_mesh_start_index, sub_mesh_end_index, texture_path, material, sub_meshes_);
SubMesh::addSubMesh(sub_mesh_start_index, sub_mesh_end_index, texture_path, material, game_material_id, sub_meshes_);
} else {
// テクスチャが同じなら、最後のサブメッシュの範囲を延長して新しい部分の終わりに合わせます。
extendLastSubMesh(sub_mesh_end_index);
Expand Down
2 changes: 1 addition & 1 deletion src/polygon_mesh/mesh_factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ namespace plateau::polygonMesh {
material = polygon.getMaterialFor(themes.at(0));
}

out_mesh.addSubMesh(texture_path, material, 0, out_mesh.getIndices().size() - 1);
out_mesh.addSubMesh(texture_path, material, 0, out_mesh.getIndices().size() - 1, -1);
}

void findAllPolygonsInGeometry(
Expand Down
2 changes: 1 addition & 1 deletion src/polygon_mesh/mesh_merger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ namespace plateau::polygonMesh {
assert(start_index <= end_index);
assert(end_index < mesh.getIndices().size());
assert((end_index - start_index + 1) % 3 == 0);
mesh.addSubMesh(texture_path, material, start_index, end_index);
mesh.addSubMesh(texture_path, material, start_index, end_index, other_sub_mesh.getGameMaterialID());
}
}

Expand Down
37 changes: 34 additions & 3 deletions src/polygon_mesh/sub_mesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,20 @@ namespace plateau::polygonMesh {
start_index_(start_index),
end_index_(end_index),
texture_path_(texture_path) ,
material_(material) {}
material_(material),
game_material_id_(-1){}

SubMesh::SubMesh(size_t start_index, size_t end_index, const std::string& texture_path,
std::shared_ptr<const citygml::Material> material, int game_material_id) :
SubMesh(start_index, end_index, texture_path, std::move(material)) {
game_material_id_ = game_material_id;
}


void
SubMesh::addSubMesh(size_t start_index, size_t end_index, const std::string& texture_path, std::shared_ptr<const citygml::Material> material, std::vector<SubMesh>& vector) {
SubMesh::addSubMesh(size_t start_index, size_t end_index, const std::string& texture_path, std::shared_ptr<const citygml::Material> material, int game_material_id, std::vector<SubMesh>& vector) {
if (end_index <= start_index) throw std::logic_error("addSubMesh : Index is invalid.");
vector.emplace_back(start_index, end_index, texture_path, material);
vector.emplace_back(start_index, end_index, texture_path, material, game_material_id);
}

size_t SubMesh::getStartIndex() const {
Expand Down Expand Up @@ -45,6 +52,30 @@ namespace plateau::polygonMesh {
end_index_ = end_index;
}

void SubMesh::setGameMaterialID(int id) {
game_material_id_ = id;
}

int SubMesh::getGameMaterialID() const {
return game_material_id_;
}

bool SubMesh::isSameAs(const SubMesh& other) const {
// ゲームマテリアルがあるなら、それ同士の比較
if(game_material_id_ >= 0 || other.game_material_id_ >= 0) {
return game_material_id_ == other.game_material_id_;
}
// materialがあるなら、それ同士の比較
if(material_ != nullptr && other.material_ != nullptr) {
return material_->getId() == other.material_->getId();
}
if(material_ == nullptr && other.material_ != nullptr || (material_ != nullptr && other.material_ == nullptr)) {
return false;
}
// 最後にテクスチャパスの比較
return texture_path_ == other.texture_path_;
}

bool SubMesh::operator==(const SubMesh& other) const{
bool ret = start_index_ == other.start_index_ &&
end_index_ == other.end_index_ &&
Expand Down
2 changes: 1 addition & 1 deletion test/test_mesh_merger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ TEST_F(MeshMergerTest, mesh_add_sub_mesh) {

auto mesh = Mesh(std::move(vertices), std::move(indices), std::move(uv_1), std::move(uv_4), std::move(sub_meshes), CityObjectList());

mesh.addSubMesh("test.png", nullptr, 3, 5);
mesh.addSubMesh("test.png", nullptr, 3, 5, -1);

const auto sub_mesh = mesh.getSubMeshes().at(1);
ASSERT_EQ("test.png", sub_mesh.getTexturePath());
Expand Down
2 changes: 1 addition & 1 deletion test/test_texture_packer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ namespace {
mesh.addVerticesList(vertices);
mesh.addIndicesList(indices, 0, false);
mesh.addUV1(uv1, vertices.size());
mesh.addSubMesh(texture_path.u8string(), nullptr, mesh.getIndices().size() - 6, mesh.getIndices().size() - 1);
mesh.addSubMesh(texture_path.u8string(), nullptr, mesh.getIndices().size() - 6, mesh.getIndices().size() - 1, -1);

base_pos = base_pos + TVec3d{2, 0, 0};
base_id += 4;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,14 @@ public void DisposeThenInvalid()
subMesh.Dispose();
Assert.ThrowsException<Exception>(() => subMesh.TexturePath, "Dispose後は情報にアクセスできない");
}

[TestMethod]
public void GetAndSetGameMaterialID()
{
var subMesh = SubMesh.Create(0, 2, "test");
Assert.AreEqual(-1, subMesh.GameMaterialID, "GameMaterialIDの初期値は-1です");
subMesh.GameMaterialID = 1;
Assert.AreEqual(1, subMesh.GameMaterialID, "GameMaterialIDのgetterとsetterが動作します");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,18 @@ public static CityObjectIndex FromUV(PlateauVector2f uv)
AtomicIndex = (int)Math.Round(uv.Y)
};
}

public override int GetHashCode()
{
return PrimaryIndex * 10000 + AtomicIndex;
}

public override bool Equals(object obj)
{
var other = obj as CityObjectIndex?;
if (other == null) return false;
return PrimaryIndex == other.Value.PrimaryIndex && AtomicIndex == other.Value.AtomicIndex;
}
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,29 @@ public PLATEAU.CityGML.Material Material
}
}

/// <summary>
/// <see cref="GameMaterialID"/>は、<see cref="SubMesh"/>にゲームエンジンのマテリアルを持たせたい場合に、
/// <see cref="TexturePath"/>や<see cref="Material"/>の代わりに利用するIDです。
/// 特に分割結合でゲームエンジンのマテリアルを維持するために利用します。
/// IDがどのマテリアルを指すかはゲームエンジンが決めます。
/// </summary>
public int GameMaterialID
{
get
{
ThrowIfInvalid();
int gameMaterialID =
DLLUtil.GetNativeValue<int>(Handle, NativeMethods.plateau_sub_mesh_get_game_material_id);
return gameMaterialID;
}
set
{
ThrowIfInvalid();
var result = NativeMethods.plateau_sub_mesh_set_game_material_id(Handle, value);
DLLUtil.CheckDllError(result);
}
}

/// <summary>
/// 取扱注意:
/// 通常は <see cref="Mesh"/> が廃棄されるときに C++側で <see cref="SubMesh"/> も廃棄されるので、
Expand Down Expand Up @@ -123,6 +146,17 @@ internal static extern APIResult plateau_sub_mesh_get_texture_path(
internal static extern APIResult plateau_sub_mesh_get_material(
[In] IntPtr subMeshPtr,
out IntPtr matPtr);

[DllImport(DLLUtil.DllName)]
internal static extern APIResult plateau_sub_mesh_set_game_material_id(
[In] IntPtr subMeshPtr,
int gameMaterialID);

[DllImport(DLLUtil.DllName)]
internal static extern APIResult plateau_sub_mesh_get_game_material_id(
[In] IntPtr subMeshPtr,
out int outGameMaterialID);


[DllImport(DLLUtil.DllName, CharSet = CharSet.Ansi)]
internal static extern APIResult plateau_create_sub_mesh(
Expand Down

0 comments on commit ae8c2e6

Please sign in to comment.