This commit is contained in:
Tsuki 2024-11-16 21:13:26 +08:00
parent b83e6d3a0f
commit 36e355335f
8 changed files with 249 additions and 107 deletions

1
Cargo.lock generated
View File

@ -1739,6 +1739,7 @@ dependencies = [
"pollster", "pollster",
"quick_cache", "quick_cache",
"regex", "regex",
"rust-embed",
"wgpu", "wgpu",
] ]

View File

@ -14,3 +14,7 @@ pollster = "0.4.0"
quick_cache = "0.6.9" quick_cache = "0.6.9"
encase = { version = "0.10.0", features = ["glam"] } encase = { version = "0.10.0", features = ["glam"] }
image = "0.25.5" image = "0.25.5"
rust-embed = "8.5.0"
[build-dependencies]
regex = "1.11.1"

122
mp_elements/build.rs Normal file
View File

@ -0,0 +1,122 @@
use regex::Regex;
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
fn main() {
let watch_dir = "shaders/elements";
for entry in fs::read_dir(watch_dir).unwrap() {
let path = entry.unwrap().path();
if path.is_file() {
println!("cargo:rerun-if-changed={}", path.display());
}
}
let crate_path = env::var("CARGO_MANIFEST_DIR").unwrap();
let shader_path_base = Path::new(&crate_path).join("shaders");
for entry in fs::read_dir(watch_dir).unwrap() {
let path = entry.unwrap().path();
if path.is_file() {
println!("cargo:rerun-if-changed={}", path.display());
}
let merged_shader = merge_shader(&path.display().to_string(), &shader_path_base);
let out_path = Path::new(&crate_path)
.join("shaders")
.join("elements")
.join(format!(
"{}_merged.wgsl",
path.file_stem().unwrap().to_str().unwrap()
));
fs::write(out_path, merged_shader).unwrap();
}
}
fn merge_shader<'a>(shader: &'a str, base: &std::path::Path) -> String {
const TOOLS: &'static str = r#"// This is a tool that merges the shader code with the shader code from the shader module.
struct UniformCommonTools {
model_matrix: mat4x4f,
view_matrix: mat4x4f,
proj_matrix: mat4x4f,
camera_x: f32,
camera_y: f32,
camera_z: f32,
camera_target_x: f32,
camera_target_y: f32,
camera_target_z: f32,
camera_up_x: f32,
camera_up_y: f32,
camera_up_z: f32,
// camera_position: vec3f,
// camera_front: vec3f,
// camera_up: vec3f,
}
@group(0) @binding(0) var<uniform> common_tools: UniformCommonTools;
"#;
let path = std::path::Path::new(shader);
let mut visited_files = std::collections::HashSet::new();
let mut result = process_file(&path, &mut visited_files, &base);
// 将工具代码插入到 shader 代码的开头
result.insert_str(0, TOOLS);
return result;
}
fn process_file<'a, P: AsRef<std::path::Path> + 'a, B: AsRef<std::path::Path>>(
file_path: P,
visited_files: &mut std::collections::HashSet<std::path::PathBuf>,
base_path: B,
) -> String {
let base_path = base_path.as_ref();
let file_path = file_path.as_ref();
// 如果该文件已经处理过,则避免死循环
if visited_files.contains(file_path) {
return String::new(); // 返回空字符串表示已经处理过
}
visited_files.insert(file_path.to_path_buf());
let content = std::fs::read_to_string(file_path).unwrap_or_else(|_| {
panic!("Failed to read file: {}", file_path.display());
});
let re = Regex::new(r#"#include\s+\"([^\"]+\.wgsl)\";"#).unwrap();
let result = re.replace_all(&content, |caps: &regex::Captures| {
let included_file = &caps[1]; // 获取文件名
let included_path = resolve_included_file(included_file, base_path.as_ref());
let included_content = process_file(
&included_path,
visited_files,
base_path.parent().unwrap_or(base_path),
);
included_content
});
result.to_string()
}
fn resolve_included_file(included_file: &str, base_path: &std::path::Path) -> std::path::PathBuf {
let included_path = std::path::Path::new(included_file);
if included_path.is_relative() {
base_path.join(included_path)
} else {
included_path.to_path_buf()
}
}

View File

@ -0,0 +1,103 @@
// This is a tool that merges the shader code with the shader code from the shader module.
struct UniformCommonTools {
model_matrix: mat4x4f,
view_matrix: mat4x4f,
proj_matrix: mat4x4f,
camera_x: f32,
camera_y: f32,
camera_z: f32,
camera_target_x: f32,
camera_target_y: f32,
camera_target_z: f32,
camera_up_x: f32,
camera_up_y: f32,
camera_up_z: f32,
// camera_position: vec3f,
// camera_front: vec3f,
// camera_up: vec3f,
}
@group(0) @binding(0) var<uniform> common_tools: UniformCommonTools;
const PI:f32 = 3.14159265358979323846264338327950288;
const TWO_PI:f32 = 6.28318530717958647692528676655900576;
const HALF_PI:f32 = 1.57079632679489661923132169163975144;
const LOG2:f32 = 0.693147180559945309417232121458176568;
const LOG10:f32 = 2.30258509299404568401799145468436421;
// Common Uniforms
// common_tools
// model_matrix: mat4,
// view_matrix: mat4,
// proj_matrix: mat4,
// camera_position: vec3,
// camera_front: vec3,
// camera_up: vec3,
// light_position: vec3,
// light_color: vec3,
// light_intensity: float,
// Uniforms
@group(1) @binding(0) var<uniform> params: UniformParams;
// Data Buffer
@group(1) @binding(1) var<storage> data: array<f32>;
struct UniformParams {
origin: vec4f
}
struct VertexOutput {
@builtin(position) position: vec4f,
@location(0) r_range: vec4f,
@location(1) idx: u32
}
@vertex
fn vertex(
@location(0) position: vec4f,
@location(1) r_range: vec4f,
// @location(2) idx: u32
) -> VertexOutput {
var out: VertexOutput;
// Transform position
out.position = common_tools.proj_matrix * common_tools.view_matrix * common_tools.model_matrix * vec4f(position, 1.0);
// out.position = vec4(position.xyz, 1.0);
out.r_range = r_range;
let idx = u32(position.w);
out.idx = idx;
return out;
}
fn polar_forward(cartesian: vec3f) -> vec3f {
let r = length(cartesian.xy - params.origin.xy);
let theta = atan2(cartesian.y, cartesian.x);
let z = cartesian.z;
return vec3f(r, theta, z);
}
@fragment
fn fragment(input: VertexOutput) -> @location(0) vec4f {
// Sample data texture
let value = data[input.idx];
let ear = polar_forward(input.position.xyz);
// var color = linear_colormap(value);
var color = clamp(value / 75.0, 0.0, 1.0);
// let r = ear.x;
// Valid range
// let r_range = input.r_range;
// let outside_lower_bound = step(r, r_range.x);
// let outside_upper_bound = step(r_range.y, r);
// let is_outside = outside_lower_bound + outside_upper_bound;
// color.a *= 1.0 - is_outside;
return vec4(color,color,color, 1.0);
}

View File

@ -1,8 +1,10 @@
use crate::Shaders;
use rust_embed::RustEmbed;
use std::{ops::Sub, result, vec}; use std::{ops::Sub, result, vec};
use crate::{ use crate::{
app::{BufferKey, Ctx, DataBufferPool}, app::{BufferKey, Ctx, DataBufferPool},
utils::merge_shader, utils::get_shader,
}; };
use bytemuck; use bytemuck;
use glam::{Vec3, Vec4}; use glam::{Vec3, Vec4};
@ -259,8 +261,9 @@ impl Element for PPI {
impl PPI { impl PPI {
fn init_shader(device: &wgpu::Device) -> wgpu::ShaderModule { fn init_shader(device: &wgpu::Device) -> wgpu::ShaderModule {
// let shader_str = merge_shader(r#"/Users/tsuki/projects/mp/mp_elements/shaders/ppi.wgsl"#); // let shader_str = merge_shader(r#"/Users/tsuki/projects/mp/mp_elements/shaders/ppi.wgsl"#);
let shader_str =
merge_shader(r#"C:\Users\qwin7\projects\radarmp\mp_elements\shaders\ppi.wgsl"#); let shader_str = get_shader("ppi_merged.wgsl").as_ref();
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("PPI Shader Module"), label: Some("PPI Shader Module"),
source: wgpu::ShaderSource::Wgsl(shader_str.into()), source: wgpu::ShaderSource::Wgsl(shader_str.into()),

View File

@ -5,3 +5,8 @@ pub mod renderer;
mod utils; mod utils;
pub use app::App; pub use app::App;
use rust_embed::RustEmbed;
#[derive(RustEmbed)]
#[folder = "shaders/"]
pub struct Shaders;

View File

@ -1,105 +1,9 @@
use std::path::PathBuf; use crate::Shaders;
use std::borrow::Cow;
use std::str;
use regex::Regex; pub fn get_shader(name: &str) -> Cow<'static, str> {
pub(crate) fn merge_shader<'a>(shader: &'a str) -> String { let file = Shaders::get(name).unwrap();
const TOOLS: &'static str = r#"// This is a tool that merges the shader code with the shader code from the shader module. let string = String::from_utf8_lossy(&file.data);
string
struct UniformCommonTools {
model_matrix: mat4x4f,
view_matrix: mat4x4f,
proj_matrix: mat4x4f,
camera_x: f32,
camera_y: f32,
camera_z: f32,
camera_target_x: f32,
camera_target_y: f32,
camera_target_z: f32,
camera_up_x: f32,
camera_up_y: f32,
camera_up_z: f32,
// camera_position: vec3f,
// camera_front: vec3f,
// camera_up: vec3f,
}
@group(0) @binding(0) var<uniform> common_tools: UniformCommonTools;
"#;
let mut visited_files = std::collections::HashSet::new();
let path: PathBuf = PathBuf::from(shader);
let base = match path.canonicalize() {
Ok(path) => path.parent().unwrap().to_owned(),
Err(e) => {
// panic!("Failed to canonicalize path: {}", e);
// PathBuf::from(r#"/Users/tsuki/projects/mp/mp_elements/shaders"#)
PathBuf::from(r#"C:\Users\qwin7\projects\radarmp\mp_elements\shaders"#)
}
};
let mut result = process_file(&path, &mut visited_files, &base);
// 将工具代码插入到 shader 代码的开头
result.insert_str(0, TOOLS);
return result;
}
fn process_file<'a, P: AsRef<std::path::Path> + 'a, B: AsRef<std::path::Path>>(
file_path: P,
visited_files: &mut std::collections::HashSet<std::path::PathBuf>,
base_path: B,
) -> String {
let base_path = base_path.as_ref();
let file_path = file_path.as_ref();
// 如果该文件已经处理过,则避免死循环
if visited_files.contains(file_path) {
return String::new(); // 返回空字符串表示已经处理过
}
visited_files.insert(file_path.to_path_buf());
let content = std::fs::read_to_string(file_path).unwrap_or_else(|_| {
panic!("Failed to read file: {}", file_path.display());
});
let re = Regex::new(r#"#include\s+\"([^\"]+\.wgsl)\";"#).unwrap();
let result = re.replace_all(&content, |caps: &regex::Captures| {
let included_file = &caps[1]; // 获取文件名
let included_path = resolve_included_file(included_file, base_path.as_ref());
let included_content = process_file(
&included_path,
visited_files,
base_path.parent().unwrap_or(base_path),
);
included_content
});
result.to_string()
}
fn resolve_included_file(included_file: &str, base_path: &std::path::Path) -> std::path::PathBuf {
let included_path = std::path::Path::new(included_file);
if included_path.is_relative() {
base_path.join(included_path)
} else {
included_path.to_path_buf()
}
}
mod test {
use super::merge_shader;
#[test]
fn test() {
let merged = merge_shader("/Users/tsuki/projects/mp/mp_elements/shaders/ppi.wgsl");
println!("{}", merged);
}
} }