Skip to content

Commit

Permalink
テクスチャスケーリング処理をglTFおよびOBJ処理にも導入する (#631)
Browse files Browse the repository at this point in the history
<!-- Close or Related Issues -->
Close #626 

### What I did(変更内容)
<!-- Please describe the motivation behind this PR and the changes it
introduces. -->
<!-- どのような変更をしますか? 目的は? -->

- objやglTFにおけるテクスチャのスケーリング対応・オプションの追加


### Notes(連絡事項)
<!-- If manual testing is required, please describe the procedure. -->
<!-- 手動での動作確認が必要なら手順を簡単に伝えてください。そのほか連絡事項など。 -->
  • Loading branch information
TadaTeruki authored Sep 1, 2024
1 parent 331c466 commit 7e77d88
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 55 deletions.
59 changes: 6 additions & 53 deletions nusamai/src/sink/cesiumtiles/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,20 +46,7 @@ use crate::{
};
use utils::calculate_normal;

const MAX_TEXTURE_PIXELS_PER_METER: f64 = 30.0;

// WARN: This function has an equivalent in `atlas-packer/src/texture.rs`.
fn uv_to_pixel_coords(uv_coords: &[(f64, f64)], width: u32, height: u32) -> Vec<(u32, u32)> {
uv_coords
.iter()
.map(|(u, v)| {
(
(u.clamp(0.0, 1.0) * width as f64).min(width as f64 - 1.0) as u32,
((1.0 - v.clamp(0.0, 1.0)) * height as f64).min(height as f64 - 1.0) as u32,
)
})
.collect()
}
use super::texture_resolution::get_texture_downsample_scale_of_polygon;

pub struct CesiumTilesSinkProvider {}

Expand Down Expand Up @@ -544,45 +531,11 @@ fn tile_writing_stage(
let texture_uri = base_texture.uri.to_file_path().unwrap();
let texture_size = texture_size_cache.get_or_insert(&texture_uri);

let pixel_coords =
uv_to_pixel_coords(&uv_coords, texture_size.0, texture_size.1);

let pixel_per_distance = (0..original_vertices.len())
.map(|i| {
let j = (i + 1) % original_vertices.len();
let (euc0, txl0) = (
(
original_vertices[i].0,
original_vertices[i].1,
original_vertices[i].2,
),
pixel_coords[i],
);
let (euc1, txl1) = (
(
original_vertices[j].0,
original_vertices[j].1,
original_vertices[j].2,
),
pixel_coords[j],
);
let euc_dist = ((euc0.0 - euc1.0).powi(2)
+ (euc0.1 - euc1.1).powi(2)
+ (euc0.2 - euc1.2).powi(2))
.sqrt();
let txl_dist = ((txl0.0 as f64 - txl1.0 as f64).powi(2)
+ (txl0.1 as f64 - txl1.1 as f64).powi(2))
.sqrt();
txl_dist / euc_dist
})
.min_by(|a, b| a.total_cmp(b))
.unwrap_or(1.0);

let downsample_scale = if limit_texture_resolution.unwrap_or(false) {
1.0_f64.min(MAX_TEXTURE_PIXELS_PER_METER / pixel_per_distance)
} else {
1.0
};
let downsample_scale = get_texture_downsample_scale_of_polygon(
&original_vertices,
texture_size,
limit_texture_resolution,
);
let factor = apply_downsample_factor(tile_zoom, downsample_scale as f32);

let downsample_factor = DownsampleFactor::new(&factor);
Expand Down
25 changes: 24 additions & 1 deletion nusamai/src/sink/gltf/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ use crate::{
transformer::{TransformerConfig, TransformerOption, TransformerRegistry},
};

use super::texture_resolution::get_texture_downsample_scale_of_polygon;

pub struct GltfSinkProvider {}

impl DataSinkProvider for GltfSinkProvider {
Expand Down Expand Up @@ -71,6 +73,16 @@ impl DataSinkProvider for GltfSinkProvider {
},
);

params.define(
"limit_texture_resolution".into(),
ParameterEntry {
description: "limiting texture resolution".into(),
required: false,
parameter: ParameterType::Boolean(BooleanParameter { value: None }),
label: Some("距離(メートル)あたりのテクスチャの解像度を制限する".into()),
},
);

params
}

Expand All @@ -89,18 +101,22 @@ impl DataSinkProvider for GltfSinkProvider {

fn create(&self, params: &Parameters) -> Box<dyn DataSink> {
let output_path = get_parameter_value!(params, "@output", FileSystemPath);
let limit_texture_resolution =
*get_parameter_value!(params, "limit_texture_resolution", Boolean);
let transform_settings = self.available_transformer();

Box::<GltfSink>::new(GltfSink {
output_path: output_path.as_ref().unwrap().into(),
transform_settings,
limit_texture_resolution,
})
}
}

pub struct GltfSink {
output_path: PathBuf,
transform_settings: TransformerRegistry,
limit_texture_resolution: Option<bool>,
}

pub struct BoundingVolume {
Expand Down Expand Up @@ -449,7 +465,14 @@ impl DataSink for GltfSink {

let texture_uri = base_texture.uri.to_file_path().unwrap();
let texture_size = texture_size_cache.get_or_insert(&texture_uri);
let downsample_factor = DownsampleFactor::new(&1.0);

let downsample_scale = get_texture_downsample_scale_of_polygon(
&original_vertices,
texture_size,
self.limit_texture_resolution,
) as f32;

let downsample_factor = DownsampleFactor::new(&downsample_scale);
let cropped_texture = CroppedTexture::new(
&texture_uri,
texture_size,
Expand Down
1 change: 1 addition & 0 deletions nusamai/src/sink/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub mod obj;
pub mod ply;
pub mod serde;
pub mod shapefile;
mod texture_resolution;

use nusamai_citygml::schema::Schema;
use nusamai_projection::crs;
Expand Down
27 changes: 26 additions & 1 deletion nusamai/src/sink/obj/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ use crate::{
transformer::{TransformerConfig, TransformerOption, TransformerRegistry},
};

use super::texture_resolution::get_texture_downsample_scale_of_polygon;

pub struct ObjSinkProvider {}

impl DataSinkProvider for ObjSinkProvider {
Expand Down Expand Up @@ -88,6 +90,16 @@ impl DataSinkProvider for ObjSinkProvider {
},
);

params.define(
"limit_texture_resolution".into(),
ParameterEntry {
description: "limiting texture resolution".into(),
required: false,
parameter: ParameterType::Boolean(BooleanParameter { value: None }),
label: Some("距離(メートル)あたりのテクスチャの解像度を制限する".into()),
},
);

params
}

Expand All @@ -106,13 +118,16 @@ impl DataSinkProvider for ObjSinkProvider {

fn create(&self, params: &Parameters) -> Box<dyn DataSink> {
let output_path = get_parameter_value!(params, "@output", FileSystemPath);
let limit_texture_resolution =
*get_parameter_value!(params, "limit_texture_resolution", Boolean);
let transform_options = self.available_transformer();
let is_split = get_parameter_value!(params, "split", Boolean).unwrap();

Box::<ObjSink>::new(ObjSink {
output_path: output_path.as_ref().unwrap().into(),
transform_settings: transform_options,
obj_options: ObjParams { is_split },
limit_texture_resolution,
})
}
}
Expand All @@ -121,6 +136,7 @@ pub struct ObjSink {
output_path: PathBuf,
transform_settings: TransformerRegistry,
obj_options: ObjParams,
limit_texture_resolution: Option<bool>,
}

struct ObjParams {
Expand Down Expand Up @@ -482,10 +498,19 @@ impl DataSink for ObjSink {
.iter()
.map(|(_, _, _, u, v)| (*u, *v))
.collect::<Vec<(f64, f64)>>();
let downsample_factor = DownsampleFactor::new(&1.0);

let texture_size =
texture_size_cache.get_or_insert(&texture_uri);
let downsample_scale = get_texture_downsample_scale_of_polygon(
&original_vertices,
texture_size,
self.limit_texture_resolution,
)
as f32;

let downsample_factor =
DownsampleFactor::new(&downsample_scale);

let texture = CroppedTexture::new(
&texture_uri,
texture_size,
Expand Down
53 changes: 53 additions & 0 deletions nusamai/src/sink/texture_resolution.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/// Limits the texture resolution based on the distance (meters) between the vertices of a polygon.
const MAX_TEXTURE_PIXELS_PER_METER: f64 = 30.0;

// WARN: This function has an equivalent in `atlas-packer/src/texture.rs`.
fn uv_to_pixel_coords(uv_coords: &[(f64, f64)], width: u32, height: u32) -> Vec<(u32, u32)> {
uv_coords
.iter()
.map(|(u, v)| {
(
(u.clamp(0.0, 1.0) * width as f64).min(width as f64 - 1.0) as u32,
((1.0 - v.clamp(0.0, 1.0)) * height as f64).min(height as f64 - 1.0) as u32,
)
})
.collect()
}

pub fn get_texture_downsample_scale_of_polygon(
vertices: &[(f64, f64, f64, f64, f64)], // (x, y, z, u, v)
texture_size: (u32, u32),
limit_texture_resolution: Option<bool>,
) -> f64 {
let uv_coords = vertices.iter().map(|v| (v.3, v.4)).collect::<Vec<_>>();

let pixel_coords = uv_to_pixel_coords(&uv_coords, texture_size.0, texture_size.1);

let pixel_per_distance = (0..vertices.len())
.map(|i| {
let j = (i + 1) % vertices.len();
let (euc0, txl0) = (
(vertices[i].0, vertices[i].1, vertices[i].2),
pixel_coords[i],
);
let (euc1, txl1) = (
(vertices[j].0, vertices[j].1, vertices[j].2),
pixel_coords[j],
);
let euc_dist =
((euc0.0 - euc1.0).powi(2) + (euc0.1 - euc1.1).powi(2) + (euc0.2 - euc1.2).powi(2))
.sqrt();
let txl_dist = ((txl0.0 as f64 - txl1.0 as f64).powi(2)
+ (txl0.1 as f64 - txl1.1 as f64).powi(2))
.sqrt();
txl_dist / euc_dist
})
.min_by(|a, b| a.total_cmp(b))
.unwrap_or(1.0);

if limit_texture_resolution.unwrap_or(false) {
1.0_f64.min(MAX_TEXTURE_PIXELS_PER_METER / pixel_per_distance)
} else {
1.0
}
}

0 comments on commit 7e77d88

Please sign in to comment.