render a cube
This commit is contained in:
parent
759b6a4211
commit
11ae302290
8
Cargo.lock
generated
8
Cargo.lock
generated
|
|
@ -6,6 +6,7 @@ version = 4
|
||||||
name = "PROJECT-NAME"
|
name = "PROJECT-NAME"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"bytemuck",
|
||||||
"glam",
|
"glam",
|
||||||
"pollster",
|
"pollster",
|
||||||
"wgpu",
|
"wgpu",
|
||||||
|
|
@ -177,9 +178,9 @@ checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytemuck"
|
name = "bytemuck"
|
||||||
version = "1.24.0"
|
version = "1.25.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4"
|
checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck_derive",
|
"bytemuck_derive",
|
||||||
]
|
]
|
||||||
|
|
@ -526,6 +527,9 @@ name = "glam"
|
||||||
version = "0.30.10"
|
version = "0.30.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "19fc433e8437a212d1b6f1e68c7824af3aed907da60afa994e7f542d18d12aa9"
|
checksum = "19fc433e8437a212d1b6f1e68c7824af3aed907da60afa994e7f542d18d12aa9"
|
||||||
|
dependencies = [
|
||||||
|
"bytemuck",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "glow"
|
name = "glow"
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ debug = false
|
||||||
opt-level = 3
|
opt-level = 3
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
glam = { version = "0.30.9" }
|
bytemuck = "1.25.2"
|
||||||
|
glam = { version = "0.30.9", features = ["bytemuck"] }
|
||||||
pollster = "0.4.0"
|
pollster = "0.4.0"
|
||||||
wgpu = "27.0.1"
|
wgpu = "27.0.1"
|
||||||
winit = "0.30.12"
|
winit = "0.30.12"
|
||||||
|
|
|
||||||
66
src/lib.rs
66
src/lib.rs
|
|
@ -1,22 +1,28 @@
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
use glam::{UVec2, Vec4, vec4};
|
use glam::{Mat4, UVec2, Vec3, Vec4, vec3, vec4};
|
||||||
|
|
||||||
mod camera;
|
mod camera;
|
||||||
|
mod render;
|
||||||
const DEPTH_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth16Unorm;
|
|
||||||
const OUTPUT_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Bgra8UnormSrgb;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct RedrawArgs {
|
pub struct RedrawArgs {
|
||||||
pub background: Vec4,
|
pub background: Vec4,
|
||||||
|
pub cam_yaw: f32,
|
||||||
|
pub cam_pitch: f32,
|
||||||
|
pub cam_distance: f32,
|
||||||
|
pub cam_fovy: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for RedrawArgs {
|
impl Default for RedrawArgs {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
background: vec4(0.05, 0.20, 0.85, 1.00),
|
background: vec4(0.05, 0.20, 0.85, 1.00),
|
||||||
|
cam_yaw: std::f32::consts::FRAC_PI_4,
|
||||||
|
cam_pitch: std::f32::consts::FRAC_PI_6,
|
||||||
|
cam_distance: 3.,
|
||||||
|
cam_fovy: std::f32::consts::FRAC_PI_2,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -32,9 +38,35 @@ pub struct Core {
|
||||||
queue: wgpu::Queue,
|
queue: wgpu::Queue,
|
||||||
surface: wgpu::Surface<'static>,
|
surface: wgpu::Surface<'static>,
|
||||||
|
|
||||||
|
mesh_pipeline: render::mesh::Pipeline,
|
||||||
|
mesh1: render::mesh::GpuMeshIndexed,
|
||||||
depth: wgpu::Texture,
|
depth: wgpu::Texture,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn cube() -> render::mesh::CpuMeshIndexed {
|
||||||
|
let mut mesh = render::mesh::CpuMeshIndexed::default();
|
||||||
|
for (u, v, w) in [
|
||||||
|
(Vec3::X, Vec3::Y, Vec3::Z),
|
||||||
|
(Vec3::Y, Vec3::Z, Vec3::X),
|
||||||
|
(Vec3::Z, Vec3::X, Vec3::Y),
|
||||||
|
] {
|
||||||
|
for (m, color) in [(1., w), (-1., 1. - w)] {
|
||||||
|
let base = mesh.vertices.len() as u16;
|
||||||
|
for offset in [m * v + u, -m * v + u, -m * v - u, m * v - u] {
|
||||||
|
let vertex = render::mesh::Vertex {
|
||||||
|
position: (m * w + offset),
|
||||||
|
color,
|
||||||
|
normal: m * w,
|
||||||
|
};
|
||||||
|
mesh.vertices.push(vertex);
|
||||||
|
}
|
||||||
|
mesh.faces.push([base, base + 1, base + 2]);
|
||||||
|
mesh.faces.push([base, base + 2, base + 3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mesh
|
||||||
|
}
|
||||||
|
|
||||||
impl Core {
|
impl Core {
|
||||||
pub fn new(gpu: Gpu, pixel_size: UVec2) -> Self {
|
pub fn new(gpu: Gpu, pixel_size: UVec2) -> Self {
|
||||||
let Gpu {
|
let Gpu {
|
||||||
|
|
@ -44,7 +76,9 @@ impl Core {
|
||||||
} = gpu;
|
} = gpu;
|
||||||
|
|
||||||
let depth = Self::create_depth_buffer(&device, pixel_size);
|
let depth = Self::create_depth_buffer(&device, pixel_size);
|
||||||
queue.submit([]); // flush buffer updates
|
let mesh_pipeline = render::mesh::Pipeline::new(&device);
|
||||||
|
let mesh1 = cube();
|
||||||
|
let mesh1 = render::mesh::GpuMeshIndexed::new(&device, &mesh1);
|
||||||
|
|
||||||
Self::configure_surface(&surface, &device, pixel_size);
|
Self::configure_surface(&surface, &device, pixel_size);
|
||||||
|
|
||||||
|
|
@ -52,6 +86,8 @@ impl Core {
|
||||||
device,
|
device,
|
||||||
queue,
|
queue,
|
||||||
surface,
|
surface,
|
||||||
|
mesh_pipeline,
|
||||||
|
mesh1,
|
||||||
depth,
|
depth,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -63,6 +99,20 @@ impl Core {
|
||||||
let h = size.height as f32;
|
let h = size.height as f32;
|
||||||
w / h
|
w / h
|
||||||
};
|
};
|
||||||
|
let view = Mat4::from(camera::view(
|
||||||
|
args.cam_yaw,
|
||||||
|
args.cam_pitch,
|
||||||
|
args.cam_distance,
|
||||||
|
));
|
||||||
|
let proj = camera::projection(args.cam_fovy, aspect);
|
||||||
|
self.mesh_pipeline.set_params(
|
||||||
|
&self.queue,
|
||||||
|
render::mesh::Params {
|
||||||
|
mvp: proj * view,
|
||||||
|
light: vec3(1., 0.5, 0.5).normalize(),
|
||||||
|
_zero: 0.,
|
||||||
|
},
|
||||||
|
);
|
||||||
self.queue.submit([]); // flush buffer updates
|
self.queue.submit([]); // flush buffer updates
|
||||||
|
|
||||||
let view = output.create_view(&wgpu::TextureViewDescriptor::default());
|
let view = output.create_view(&wgpu::TextureViewDescriptor::default());
|
||||||
|
|
@ -97,7 +147,7 @@ impl Core {
|
||||||
}),
|
}),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
|
self.mesh1.render(&self.mesh_pipeline, &mut pass);
|
||||||
drop(pass);
|
drop(pass);
|
||||||
self.queue.submit(std::iter::once(encoder.finish()));
|
self.queue.submit(std::iter::once(encoder.finish()));
|
||||||
}
|
}
|
||||||
|
|
@ -113,7 +163,7 @@ impl Core {
|
||||||
mip_level_count: 1,
|
mip_level_count: 1,
|
||||||
sample_count: 1,
|
sample_count: 1,
|
||||||
dimension: wgpu::TextureDimension::D2,
|
dimension: wgpu::TextureDimension::D2,
|
||||||
format: DEPTH_FORMAT,
|
format: render::DEPTH_FORMAT,
|
||||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||||
view_formats: &[],
|
view_formats: &[],
|
||||||
})
|
})
|
||||||
|
|
@ -124,7 +174,7 @@ impl Core {
|
||||||
device,
|
device,
|
||||||
&wgpu::SurfaceConfiguration {
|
&wgpu::SurfaceConfiguration {
|
||||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_DST,
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_DST,
|
||||||
format: OUTPUT_FORMAT,
|
format: render::OUTPUT_FORMAT,
|
||||||
width: pixel_size.x,
|
width: pixel_size.x,
|
||||||
height: pixel_size.y,
|
height: pixel_size.y,
|
||||||
present_mode: wgpu::PresentMode::Fifo,
|
present_mode: wgpu::PresentMode::Fifo,
|
||||||
|
|
|
||||||
209
src/render/mesh.rs
Normal file
209
src/render/mesh.rs
Normal file
|
|
@ -0,0 +1,209 @@
|
||||||
|
use std::mem::offset_of;
|
||||||
|
|
||||||
|
use bytemuck::{Pod, Zeroable, bytes_of, cast_slice};
|
||||||
|
use glam::{Mat4, Vec3};
|
||||||
|
use wgpu::util::DeviceExt;
|
||||||
|
|
||||||
|
static SHADER: &str = include_str!("mesh.wgsl");
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Zeroable, Pod)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct Vertex {
|
||||||
|
pub position: Vec3,
|
||||||
|
pub color: Vec3,
|
||||||
|
pub normal: Vec3,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Zeroable, Pod)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct Params {
|
||||||
|
pub mvp: Mat4,
|
||||||
|
pub light: Vec3,
|
||||||
|
pub _zero: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default)]
|
||||||
|
pub struct CpuMesh {
|
||||||
|
pub faces: Vec<[Vertex; 3]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default)]
|
||||||
|
pub struct CpuMeshIndexed {
|
||||||
|
pub vertices: Vec<Vertex>,
|
||||||
|
pub faces: Vec<[u16; 3]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct GpuMesh {
|
||||||
|
vertices: wgpu::Buffer,
|
||||||
|
vertex_count: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct GpuMeshIndexed {
|
||||||
|
vertices: wgpu::Buffer,
|
||||||
|
indices: wgpu::Buffer,
|
||||||
|
index_count: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GpuMesh {
|
||||||
|
pub fn new(device: &wgpu::Device, data: &CpuMesh) -> Self {
|
||||||
|
let vertices = cast_slice::<_, Vertex>(&data.faces);
|
||||||
|
let vertex_count = vertices.len().try_into().expect("too many faces");
|
||||||
|
let vertices = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
|
label: None,
|
||||||
|
usage: wgpu::BufferUsages::VERTEX,
|
||||||
|
contents: cast_slice(&vertices),
|
||||||
|
});
|
||||||
|
Self {
|
||||||
|
vertices,
|
||||||
|
vertex_count,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GpuMeshIndexed {
|
||||||
|
pub fn new(device: &wgpu::Device, data: &CpuMeshIndexed) -> Self {
|
||||||
|
let vertex_count = data.vertices.len();
|
||||||
|
if vertex_count >= 1 << 16 {
|
||||||
|
panic!("too many vertices");
|
||||||
|
}
|
||||||
|
let indices = cast_slice::<_, u16>(&data.faces);
|
||||||
|
let index_count = indices.len().try_into().expect("too many faces");
|
||||||
|
for index in indices {
|
||||||
|
if *index as usize >= vertex_count {
|
||||||
|
panic!("vertex index out of bounds: {index} out of {vertex_count}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let vertices = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
|
label: None,
|
||||||
|
usage: wgpu::BufferUsages::VERTEX,
|
||||||
|
contents: cast_slice(&data.vertices),
|
||||||
|
});
|
||||||
|
let indices = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
|
label: None,
|
||||||
|
usage: wgpu::BufferUsages::INDEX,
|
||||||
|
contents: cast_slice(&indices),
|
||||||
|
});
|
||||||
|
Self {
|
||||||
|
vertices,
|
||||||
|
indices,
|
||||||
|
index_count,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Pipeline {
|
||||||
|
params: wgpu::Buffer,
|
||||||
|
bindings: wgpu::BindGroup,
|
||||||
|
pipeline: wgpu::RenderPipeline,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Pipeline {
|
||||||
|
pub fn new(device: &wgpu::Device) -> Self {
|
||||||
|
let params = device.create_buffer(&wgpu::BufferDescriptor {
|
||||||
|
label: None,
|
||||||
|
size: size_of::<Params>() as u64,
|
||||||
|
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
|
||||||
|
mapped_at_creation: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||||
|
label: None,
|
||||||
|
source: wgpu::ShaderSource::Wgsl(SHADER.into()),
|
||||||
|
});
|
||||||
|
let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||||
|
label: None,
|
||||||
|
layout: None,
|
||||||
|
vertex: wgpu::VertexState {
|
||||||
|
module: &shader,
|
||||||
|
entry_point: None,
|
||||||
|
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||||
|
buffers: &[wgpu::VertexBufferLayout {
|
||||||
|
array_stride: size_of::<Vertex>() as u64,
|
||||||
|
step_mode: wgpu::VertexStepMode::Vertex,
|
||||||
|
attributes: &[
|
||||||
|
wgpu::VertexAttribute {
|
||||||
|
shader_location: 0,
|
||||||
|
offset: offset_of!(Vertex, position) as u64,
|
||||||
|
format: wgpu::VertexFormat::Float32x3,
|
||||||
|
},
|
||||||
|
wgpu::VertexAttribute {
|
||||||
|
shader_location: 1,
|
||||||
|
offset: offset_of!(Vertex, color) as u64,
|
||||||
|
format: wgpu::VertexFormat::Float32x3,
|
||||||
|
},
|
||||||
|
wgpu::VertexAttribute {
|
||||||
|
shader_location: 2,
|
||||||
|
offset: offset_of!(Vertex, normal) as u64,
|
||||||
|
format: wgpu::VertexFormat::Float32x3,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
primitive: wgpu::PrimitiveState {
|
||||||
|
topology: wgpu::PrimitiveTopology::TriangleList,
|
||||||
|
cull_mode: Some(wgpu::Face::Back),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
depth_stencil: Some(wgpu::DepthStencilState {
|
||||||
|
format: crate::render::DEPTH_FORMAT,
|
||||||
|
depth_write_enabled: true,
|
||||||
|
depth_compare: wgpu::CompareFunction::LessEqual,
|
||||||
|
stencil: wgpu::StencilState::default(),
|
||||||
|
bias: wgpu::DepthBiasState::default(),
|
||||||
|
}),
|
||||||
|
multisample: wgpu::MultisampleState {
|
||||||
|
count: 1,
|
||||||
|
mask: !0,
|
||||||
|
alpha_to_coverage_enabled: false,
|
||||||
|
},
|
||||||
|
fragment: Some(wgpu::FragmentState {
|
||||||
|
module: &shader,
|
||||||
|
entry_point: None,
|
||||||
|
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||||
|
targets: &[Some(wgpu::ColorTargetState {
|
||||||
|
format: crate::render::OUTPUT_FORMAT,
|
||||||
|
blend: Some(wgpu::BlendState::REPLACE),
|
||||||
|
write_mask: wgpu::ColorWrites::ALL,
|
||||||
|
})],
|
||||||
|
}),
|
||||||
|
multiview: None,
|
||||||
|
cache: None,
|
||||||
|
});
|
||||||
|
let bindings = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||||
|
label: None,
|
||||||
|
layout: &pipeline.get_bind_group_layout(0),
|
||||||
|
entries: &[wgpu::BindGroupEntry {
|
||||||
|
binding: 0,
|
||||||
|
resource: params.as_entire_binding(),
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
Self {
|
||||||
|
params,
|
||||||
|
bindings,
|
||||||
|
pipeline,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_params(&self, queue: &wgpu::Queue, params: Params) {
|
||||||
|
queue.write_buffer(&self.params, 0, bytes_of(¶ms));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GpuMesh {
|
||||||
|
pub fn render(&self, pipeline: &Pipeline, pass: &mut wgpu::RenderPass) {
|
||||||
|
pass.set_pipeline(&pipeline.pipeline);
|
||||||
|
pass.set_bind_group(0, &pipeline.bindings, &[]);
|
||||||
|
pass.set_vertex_buffer(0, self.vertices.slice(..));
|
||||||
|
pass.draw(0..self.vertex_count, 0..1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GpuMeshIndexed {
|
||||||
|
pub fn render(&self, pipeline: &Pipeline, pass: &mut wgpu::RenderPass) {
|
||||||
|
pass.set_pipeline(&pipeline.pipeline);
|
||||||
|
pass.set_bind_group(0, &pipeline.bindings, &[]);
|
||||||
|
pass.set_vertex_buffer(0, self.vertices.slice(..));
|
||||||
|
pass.set_index_buffer(self.indices.slice(..), wgpu::IndexFormat::Uint16);
|
||||||
|
pass.draw_indexed(0..self.index_count, 0, 0..1);
|
||||||
|
}
|
||||||
|
}
|
||||||
36
src/render/mesh.wgsl
Normal file
36
src/render/mesh.wgsl
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
struct Params {
|
||||||
|
mvp: mat4x4f,
|
||||||
|
light: vec3f,
|
||||||
|
_zero: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Vertex {
|
||||||
|
@location(0) position: vec3f,
|
||||||
|
@location(1) color: vec3f,
|
||||||
|
@location(2) normal: vec3f,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Varying {
|
||||||
|
@builtin(position) screen: vec4f,
|
||||||
|
@location(0) color: vec4f,
|
||||||
|
@location(1) normal: vec3f,
|
||||||
|
}
|
||||||
|
|
||||||
|
@group(0) @binding(0) var<uniform> params: Params;
|
||||||
|
|
||||||
|
@vertex
|
||||||
|
fn on_vertex(in: Vertex) -> Varying {
|
||||||
|
let position = params.mvp * vec4f(in.position, 1.0);
|
||||||
|
let color = vec4f(in.color, 1.0);
|
||||||
|
let normal = in.normal;
|
||||||
|
return Varying(position, color, normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
@fragment
|
||||||
|
fn on_fragment(in: Varying) -> @location(0) vec4f {
|
||||||
|
let normal = normalize(in.normal);
|
||||||
|
let light = dot(params.light, normal);
|
||||||
|
let u = 0.5 + 0.5 * light;
|
||||||
|
let color = vec4f(u * in.color.xyz, in.color.w);
|
||||||
|
return color;
|
||||||
|
}
|
||||||
4
src/render/mod.rs
Normal file
4
src/render/mod.rs
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
pub mod mesh;
|
||||||
|
|
||||||
|
pub const DEPTH_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth24Plus;
|
||||||
|
pub const OUTPUT_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Bgra8UnormSrgb;
|
||||||
|
|
@ -13,6 +13,10 @@ struct Core;
|
||||||
|
|
||||||
struct RedrawArgs {
|
struct RedrawArgs {
|
||||||
Vec4 background;
|
Vec4 background;
|
||||||
|
float cam_yaw;
|
||||||
|
float cam_pitch;
|
||||||
|
float cam_distance;
|
||||||
|
float cam_fovy;
|
||||||
};
|
};
|
||||||
} // namespace ffi
|
} // namespace ffi
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,10 @@ void PROJECTNAME::updateView() {
|
||||||
const auto color = m_ui->inBackground->color();
|
const auto color = m_ui->inBackground->color();
|
||||||
RedrawArgs args{
|
RedrawArgs args{
|
||||||
.background = { color.redF(), color.greenF(), color.blueF(), 1.00 },
|
.background = { color.redF(), color.greenF(), color.blueF(), 1.00 },
|
||||||
|
.cam_yaw = qDegreesToRadians((float)m_ui->camYaw->value()),
|
||||||
|
.cam_pitch = qDegreesToRadians((float)m_ui->camPitch->value()),
|
||||||
|
.cam_distance = (float)m_ui->camDistance->value(),
|
||||||
|
.cam_fovy = qDegreesToRadians((float)m_ui->camFoV->value()),
|
||||||
};
|
};
|
||||||
m_ui->viewport->setView(args);
|
m_ui->viewport->setView(args);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,20 +26,136 @@
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>1600</width>
|
<width>1600</width>
|
||||||
<height>34</height>
|
<height>33</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QStatusBar" name="statusbar"/>
|
<widget class="QStatusBar" name="statusbar"/>
|
||||||
<widget class="QDockWidget" name="dockWidget">
|
<widget class="QDockWidget" name="dockWidget">
|
||||||
<property name="features">
|
<property name="features">
|
||||||
<set>QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable</set>
|
<set>QDockWidget::DockWidgetFeature::DockWidgetFloatable|QDockWidget::DockWidgetFeature::DockWidgetMovable</set>
|
||||||
</property>
|
</property>
|
||||||
<attribute name="dockWidgetArea">
|
<attribute name="dockWidgetArea">
|
||||||
<number>2</number>
|
<number>2</number>
|
||||||
</attribute>
|
</attribute>
|
||||||
<widget class="QWidget" name="dockWidgetContents">
|
<widget class="QWidget" name="dockWidgetContents">
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Camera</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Yaw</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDoubleSpinBox" name="camYaw">
|
||||||
|
<property name="suffix">
|
||||||
|
<string> °</string>
|
||||||
|
</property>
|
||||||
|
<property name="decimals">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<double>-180.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<double>180.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="singleStep">
|
||||||
|
<double>5.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<double>45.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>Pitch</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDoubleSpinBox" name="camPitch">
|
||||||
|
<property name="suffix">
|
||||||
|
<string> °</string>
|
||||||
|
</property>
|
||||||
|
<property name="decimals">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<double>-90.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<double>90.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="singleStep">
|
||||||
|
<double>5.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<double>30.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_5">
|
||||||
|
<property name="text">
|
||||||
|
<string>Distance</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDoubleSpinBox" name="camDistance">
|
||||||
|
<property name="maximum">
|
||||||
|
<double>10.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="stepType">
|
||||||
|
<enum>QAbstractSpinBox::StepType::AdaptiveDecimalStepType</enum>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<double>4.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="text">
|
||||||
|
<string>Field of view</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDoubleSpinBox" name="camFoV">
|
||||||
|
<property name="suffix">
|
||||||
|
<string> °</string>
|
||||||
|
</property>
|
||||||
|
<property name="decimals">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<double>15.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<double>150.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="singleStep">
|
||||||
|
<double>5.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<double>90.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label">
|
<widget class="QLabel" name="label">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
|
@ -51,9 +167,9 @@
|
||||||
<widget class="KColorCombo" name="inBackground">
|
<widget class="KColorCombo" name="inBackground">
|
||||||
<property name="color">
|
<property name="color">
|
||||||
<color>
|
<color>
|
||||||
<red>25</red>
|
<red>0</red>
|
||||||
<green>220</green>
|
<green>32</green>
|
||||||
<blue>0</blue>
|
<blue>60</blue>
|
||||||
</color>
|
</color>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
|
|
@ -106,6 +222,70 @@
|
||||||
</hint>
|
</hint>
|
||||||
</hints>
|
</hints>
|
||||||
</connection>
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>camYaw</sender>
|
||||||
|
<signal>valueChanged(double)</signal>
|
||||||
|
<receiver>MainWindow</receiver>
|
||||||
|
<slot>updateView()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>1507</x>
|
||||||
|
<y>136</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>1475</x>
|
||||||
|
<y>183</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>camPitch</sender>
|
||||||
|
<signal>valueChanged(double)</signal>
|
||||||
|
<receiver>MainWindow</receiver>
|
||||||
|
<slot>updateView()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>1507</x>
|
||||||
|
<y>214</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>1479</x>
|
||||||
|
<y>280</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>camDistance</sender>
|
||||||
|
<signal>valueChanged(double)</signal>
|
||||||
|
<receiver>MainWindow</receiver>
|
||||||
|
<slot>updateView()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>1536</x>
|
||||||
|
<y>260</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>1478</x>
|
||||||
|
<y>345</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>camFoV</sender>
|
||||||
|
<signal>valueChanged(double)</signal>
|
||||||
|
<receiver>MainWindow</receiver>
|
||||||
|
<slot>updateView()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>1541</x>
|
||||||
|
<y>325</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>1476</x>
|
||||||
|
<y>432</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
</connections>
|
</connections>
|
||||||
<slots>
|
<slots>
|
||||||
<slot>updateView()</slot>
|
<slot>updateView()</slot>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user