Skip to content

Commit

Permalink
テクスチャのスケーリング (#586) (#623)
Browse files Browse the repository at this point in the history
<!-- Close or Related Issues -->
Close #586

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

各ポリゴンについて、一定の距離に対するテクスチャのピクセルの数を制限し、制限を超える場合はテクスチャをスケーリングします。

(文章が長くなるので、距離ごとのピクセル数 = PD とします)

具体的な処理を述べると
-
各ポリゴンに対して、構成するvertexの(x,y,z,u,v)から、各辺のユークリッド空間上の距離とテクスチャ上の距離(ピクセル数)を割り出します。その後、各辺ごとのPD(=ピクセル数/ユークリッド距離)の最小値を割り出し、これをポリゴン全体のPDとしています。
-  PDの制限値としてMaxPDを設けます (例えばMaxPD=6のときは、許容するPDの最大値が6となります) 。
-
MaxPD/PDを求めます。これが1を下回る場合(=テクスチャの解像度が過剰である場合)は、テクスチャのdownsampleの倍率に適用されます。


### Notes(連絡事項)
<!-- If manual testing is required, please describe the procedure. -->
<!-- 手動での動作確認が必要なら手順を簡単に伝えてください。そのほか連絡事項など。 -->

- uv座標をテクスチャのピクセルの座標に変える処理
(`uv_to_pixel_coords`)を追加しているのですが、`atlas-packer`側の実装と重複しています。ここは仕様が頻りに変わる処理ではなく、`atlas-packer`側の実装を変更してまでDRYを貫く必要性はないと感じているため、ここでは一旦重複した状態のままでコミットしています。
-
現状MaxPDの具体的な数値は、外部からの入力でなく、定数`MAX_PIXEL_PER_DISTANCE`として宣言しています(=15.0)。

---------

Co-authored-by: nokonoko1203 <healtheworld.1203@gmail.com>
  • Loading branch information
TadaTeruki and nokonoko1203 authored Aug 28, 2024
1 parent 45f48bc commit 864125e
Showing 1 changed file with 60 additions and 4 deletions.
64 changes: 60 additions & 4 deletions nusamai/src/sink/cesiumtiles/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,21 @@ use crate::{
};
use utils::calculate_normal;

const MAX_PIXEL_PER_DISTANCE: 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 struct CesiumTilesSinkProvider {}

impl DataSinkProvider for CesiumTilesSinkProvider {
Expand Down Expand Up @@ -502,14 +517,54 @@ fn tile_writing_stage(
.iter()
.map(|[x, y, z, u, v]| (*x, *y, *z, *u, *v))
.collect::<Vec<(f64, f64, f64, f64, f64)>>();

let uv_coords = original_vertices
.iter()
.map(|(_, _, _, u, v)| (*u, *v))
.collect::<Vec<(f64, f64)>>();

let texture_uri = base_texture.uri.to_file_path().unwrap();
let texture_size = texture_size_cache.get_or_insert(&texture_uri);
let factor = apply_downsample_factor(tile_zoom);

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 max_pixel_per_distance = MAX_PIXEL_PER_DISTANCE;
let downsample_scale =
(1.0_f64).min(max_pixel_per_distance / pixel_per_distance);
let factor = apply_downsample_factor(tile_zoom, downsample_scale as f32);

let downsample_factor = DownsampleFactor::new(&factor);
let cropped_texture = CroppedTexture::new(
&texture_uri,
Expand Down Expand Up @@ -675,11 +730,12 @@ fn tile_writing_stage(
Ok(())
}

fn apply_downsample_factor(z: u8) -> f32 {
match z {
fn apply_downsample_factor(z: u8, downsample_scale: f32) -> f32 {
let f = match z {
0..=14 => 0.0,
15..=16 => 0.25,
17 => 0.5,
_ => 1.0,
}
};
f * downsample_scale
}

0 comments on commit 864125e

Please sign in to comment.