|
| 1 | +// Copyright 2016 The Gfx-rs Developers. |
| 2 | +// |
| 3 | +// Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | +// you may not use this file except in compliance with the License. |
| 5 | +// You may obtain a copy of the License at |
| 6 | +// |
| 7 | +// http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | +// |
| 9 | +// Unless required by applicable law or agreed to in writing, software |
| 10 | +// distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | +// See the License for the specific language governing permissions and |
| 13 | +// limitations under the License. |
| 14 | + |
| 15 | +#[macro_use] |
| 16 | +extern crate gfx; |
| 17 | +extern crate gfx_app; |
| 18 | +extern crate cgmath; |
| 19 | + |
| 20 | +pub use gfx_app::ColorFormat; |
| 21 | +pub use gfx::format::{Depth, Rgba8}; |
| 22 | + |
| 23 | +use cgmath::{Deg, Matrix4}; |
| 24 | +use gfx::{Bundle, texture, memory, format, handle, state}; |
| 25 | +use std::time::Instant; |
| 26 | + |
| 27 | +gfx_defines!{ |
| 28 | + vertex Vertex { |
| 29 | + pos: [f32; 2] = "a_Pos", |
| 30 | + } |
| 31 | + |
| 32 | + constant Locals { |
| 33 | + inv_proj: [[f32; 4]; 4] = "u_InvProj", |
| 34 | + view: [[f32; 4]; 4] = "u_WorldToCamera", |
| 35 | + } |
| 36 | + |
| 37 | + pipeline pipe { |
| 38 | + vbuf: gfx::VertexBuffer<Vertex> = (), |
| 39 | + cubemap: gfx::TextureSampler<[f32; 4]> = "t_Cubemap", |
| 40 | + locals: gfx::ConstantBuffer<Locals> = "Locals", |
| 41 | + out: gfx::RenderTarget<ColorFormat> = "Target0", |
| 42 | + } |
| 43 | +} |
| 44 | + |
| 45 | +gfx_defines! { |
| 46 | + vertex VertexRender { |
| 47 | + pos: [f32; 3] = "a_Pos", |
| 48 | + } |
| 49 | + |
| 50 | + constant LocalsRender { |
| 51 | + pos: [f32; 3] = "pos", |
| 52 | + far_plane: f32 = "farPlane", |
| 53 | + } |
| 54 | + |
| 55 | + constant Matrix { |
| 56 | + matrix: [[f32; 4]; 4] = "matrix", |
| 57 | + } |
| 58 | + |
| 59 | + pipeline pipe_render { |
| 60 | + vbuf: gfx::VertexBuffer<VertexRender> = (), |
| 61 | + locals: gfx::ConstantBuffer<LocalsRender> = "Locals", |
| 62 | + matrices: gfx::ConstantBuffer<Matrix> = "u_Matrices", |
| 63 | + out_depth: gfx::DepthTarget<DepthFormat> = gfx::preset::depth::LESS_EQUAL_WRITE, |
| 64 | + } |
| 65 | +} |
| 66 | + |
| 67 | +impl From<cgmath::Matrix4<f32>> for Matrix { |
| 68 | + fn from(m: cgmath::Matrix4<f32>) -> Self { |
| 69 | + Matrix { matrix: m.into() } |
| 70 | + } |
| 71 | +} |
| 72 | + |
| 73 | +impl Vertex { |
| 74 | + fn new(p: [f32; 2]) -> Vertex { |
| 75 | + Vertex { pos: p } |
| 76 | + } |
| 77 | +} |
| 78 | + |
| 79 | +impl VertexRender { |
| 80 | + fn new(p: [f32; 3]) -> VertexRender { |
| 81 | + VertexRender { pos: p } |
| 82 | + } |
| 83 | +} |
| 84 | + |
| 85 | +pub struct DepthFormat; |
| 86 | + |
| 87 | +impl format::Formatted for DepthFormat { |
| 88 | + type Surface = format::D24_S8; |
| 89 | + type Channel = format::Unorm; |
| 90 | + type View = [f32; 4]; |
| 91 | + |
| 92 | + fn get_format() -> format::Format { |
| 93 | + format::Format(format::SurfaceType::D24_S8, format::ChannelType::Unorm) |
| 94 | + } |
| 95 | +} |
| 96 | + |
| 97 | +fn create_cubemap<R, F, DF>( |
| 98 | + factory: &mut F, |
| 99 | + size: texture::Size, |
| 100 | +) -> Result< |
| 101 | + (handle::ShaderResourceView<R, DF::View>, handle::DepthStencilView<R, DF>), |
| 102 | + gfx::CombinedError, |
| 103 | +> |
| 104 | +where |
| 105 | + R: gfx::Resources, |
| 106 | + F: gfx::Factory<R>, |
| 107 | + DF: format::DepthFormat + format::TextureFormat, |
| 108 | +{ |
| 109 | + // Get texture info |
| 110 | + let kind = texture::Kind::Cube(size); |
| 111 | + let levels = 1; |
| 112 | + let bind = gfx::DEPTH_STENCIL | gfx::SHADER_RESOURCE; |
| 113 | + let channel_type = <DF::Channel as format::ChannelTyped>::get_channel_type(); |
| 114 | + |
| 115 | + // Create texture |
| 116 | + let texture = factory.create_texture( |
| 117 | + kind, |
| 118 | + levels, |
| 119 | + bind, |
| 120 | + memory::Usage::Data, |
| 121 | + Some(channel_type), |
| 122 | + )?; |
| 123 | + |
| 124 | + // View the texture as a shader resource |
| 125 | + let srv = factory.view_texture_as_shader_resource::<DF>( |
| 126 | + &texture, |
| 127 | + (0, 0), |
| 128 | + format::Swizzle::new(), |
| 129 | + )?; |
| 130 | + |
| 131 | + // View the texture as a depth stencil |
| 132 | + let dsv = factory.view_texture_as_depth_stencil_trivial(&texture)?; |
| 133 | + |
| 134 | + Ok((srv, dsv)) |
| 135 | +} |
| 136 | + |
| 137 | +struct App<R: gfx::Resources> { |
| 138 | + bundle: Bundle<R, pipe::Data<R>>, |
| 139 | + bundle_render_cubemap: Bundle<R, pipe_render::Data<R>>, |
| 140 | + projection: Matrix4<f32>, |
| 141 | + proj_render: Matrix4<f32>, |
| 142 | + far_plane: f32, |
| 143 | + start_time: Instant, |
| 144 | +} |
| 145 | + |
| 146 | +impl<R: gfx::Resources> gfx_app::Application<R> for App<R> { |
| 147 | + fn new<F: gfx::Factory<R>>( |
| 148 | + factory: &mut F, |
| 149 | + backend: gfx_app::shade::Backend, |
| 150 | + window_targets: gfx_app::WindowTargets<R>, |
| 151 | + ) -> Self { |
| 152 | + use gfx::traits::FactoryExt; |
| 153 | + |
| 154 | + let proj = cgmath::perspective(Deg(90.0f32), window_targets.aspect_ratio, 0.01, 100.0); |
| 155 | + |
| 156 | + let (bundle_skybox, dsv) = { |
| 157 | + let vs = gfx_app::shade::Source { |
| 158 | + glsl_150: include_bytes!("shader/cubemap_150.glslv"), |
| 159 | + hlsl_40: include_bytes!("data/vertex.fx"), |
| 160 | + ..gfx_app::shade::Source::empty() |
| 161 | + }; |
| 162 | + let ps = gfx_app::shade::Source { |
| 163 | + glsl_150: include_bytes!("shader/cubemap_150.glslf"), |
| 164 | + hlsl_40: include_bytes!("data/pixel.fx"), |
| 165 | + ..gfx_app::shade::Source::empty() |
| 166 | + }; |
| 167 | + |
| 168 | + let vertex_data = [ |
| 169 | + Vertex::new([-1.0, -1.0]), |
| 170 | + Vertex::new([3.0, -1.0]), |
| 171 | + Vertex::new([-1.0, 3.0]), |
| 172 | + ]; |
| 173 | + let (vbuf, slice) = factory.create_vertex_buffer_with_slice(&vertex_data, ()); |
| 174 | + |
| 175 | + let (cubemap, dsv) = create_cubemap::<_, _, DepthFormat>(factory, 1024).unwrap(); |
| 176 | + |
| 177 | + let sampler = factory.create_sampler_linear(); |
| 178 | + |
| 179 | + let pso = factory |
| 180 | + .create_pipeline_simple( |
| 181 | + vs.select(backend).unwrap(), |
| 182 | + ps.select(backend).unwrap(), |
| 183 | + pipe::new(), |
| 184 | + ) |
| 185 | + .unwrap(); |
| 186 | + |
| 187 | + let data = pipe::Data { |
| 188 | + vbuf: vbuf, |
| 189 | + cubemap: (cubemap, sampler), |
| 190 | + locals: factory.create_constant_buffer(1), |
| 191 | + out: window_targets.color, |
| 192 | + }; |
| 193 | + |
| 194 | + (Bundle::new(slice, pso, data), dsv) |
| 195 | + }; |
| 196 | + |
| 197 | + let bundle_render_cubemap = { |
| 198 | + let vs = gfx_app::shade::Source { |
| 199 | + glsl_150: include_bytes!("shader/render_150.glslv"), |
| 200 | + ..gfx_app::shade::Source::empty() |
| 201 | + }; |
| 202 | + let gs = gfx_app::shade::Source { |
| 203 | + glsl_150: include_bytes!("shader/render_150.glslg"), |
| 204 | + ..gfx_app::shade::Source::empty() |
| 205 | + }; |
| 206 | + let ps = gfx_app::shade::Source { |
| 207 | + glsl_150: include_bytes!("shader/render_150.glslf"), |
| 208 | + ..gfx_app::shade::Source::empty() |
| 209 | + }; |
| 210 | + |
| 211 | + let vertex_data = [ |
| 212 | + VertexRender::new([0.0, 0.0, 1.0]), |
| 213 | + VertexRender::new([1.0, 1.0, 0.0]), |
| 214 | + VertexRender::new([1.0, -1.0, 0.0]), |
| 215 | + ]; |
| 216 | + |
| 217 | + let (vbuf, slice) = factory.create_vertex_buffer_with_slice(&vertex_data, ()); |
| 218 | + |
| 219 | + let vs = factory |
| 220 | + .create_shader_vertex(&vs.select(backend).unwrap()) |
| 221 | + .unwrap(); |
| 222 | + let gs = factory |
| 223 | + .create_shader_geometry(&gs.select(backend).unwrap()) |
| 224 | + .unwrap(); |
| 225 | + let ps = factory |
| 226 | + .create_shader_pixel(&ps.select(backend).unwrap()) |
| 227 | + .unwrap(); |
| 228 | + let set = gfx::ShaderSet::Geometry(vs, gs, ps); |
| 229 | + |
| 230 | + let pso = factory |
| 231 | + .create_pipeline_state( |
| 232 | + &set, |
| 233 | + gfx::Primitive::TriangleList, |
| 234 | + state::Rasterizer::new_fill(), |
| 235 | + pipe_render::new(), |
| 236 | + ) |
| 237 | + .unwrap(); |
| 238 | + |
| 239 | + let data = pipe_render::Data { |
| 240 | + vbuf: vbuf, |
| 241 | + locals: factory.create_constant_buffer(1), |
| 242 | + matrices: factory.create_constant_buffer(6), |
| 243 | + out_depth: dsv, |
| 244 | + }; |
| 245 | + |
| 246 | + Bundle::new(slice, pso, data) |
| 247 | + |
| 248 | + }; |
| 249 | + |
| 250 | + let far_plane = 10.0; |
| 251 | + let proj_render = cgmath::perspective( |
| 252 | + cgmath::Deg(90.0), |
| 253 | + window_targets.aspect_ratio, |
| 254 | + 0.1, |
| 255 | + far_plane, |
| 256 | + ); |
| 257 | + |
| 258 | + App { |
| 259 | + bundle: bundle_skybox, |
| 260 | + bundle_render_cubemap, |
| 261 | + projection: proj, |
| 262 | + start_time: Instant::now(), |
| 263 | + proj_render: proj_render, |
| 264 | + far_plane, |
| 265 | + } |
| 266 | + } |
| 267 | + |
| 268 | + fn render<C: gfx::CommandBuffer<R>>(&mut self, encoder: &mut gfx::Encoder<R, C>) { |
| 269 | + use cgmath::{Matrix4, Point3, SquareMatrix, Vector3, vec3}; |
| 270 | + |
| 271 | + encoder.clear(&self.bundle.data.out, [0.3, 0.3, 0.3, 1.0]); |
| 272 | + self.bundle.encode(encoder); |
| 273 | + |
| 274 | + // Render to the render target |
| 275 | + { |
| 276 | + encoder.clear_depth(&self.bundle_render_cubemap.data.out_depth, 1.0); |
| 277 | + |
| 278 | + let far_plane = 10.0; |
| 279 | + let pos = Point3::new(0.0, 0.0, 0.0); |
| 280 | + |
| 281 | + let mut matrices: [Matrix; 6] = |
| 282 | + [ |
| 283 | + Matrix4::look_at(pos, pos + vec3(1.0, 0.0, 0.0), vec3(0.0, -1.0, 0.0)).into(), |
| 284 | + Matrix4::look_at(pos, pos + vec3(-1.0, 0.0, 0.0), vec3(0.0, -1.0, 0.0)).into(), |
| 285 | + Matrix4::look_at(pos, pos + vec3(0.0, 1.0, 0.0), vec3(0.0, 0.0, 1.0)).into(), |
| 286 | + Matrix4::look_at(pos, pos + vec3(0.0, -1.0, 0.0), vec3(0.0, 0.0, -1.0)).into(), |
| 287 | + Matrix4::look_at(pos, pos + vec3(0.0, 0.0, 1.0), vec3(0.0, -1.0, 0.0)).into(), |
| 288 | + Matrix4::look_at(pos, pos + vec3(0.0, 0.0, -1.0), vec3(0.0, -1.0, 0.0)).into(), |
| 289 | + ]; |
| 290 | + |
| 291 | + for m in &mut matrices { |
| 292 | + m.matrix = (self.proj_render * Matrix4::from(m.matrix)).into(); |
| 293 | + } |
| 294 | + |
| 295 | + let locals = LocalsRender { |
| 296 | + pos: pos.into(), |
| 297 | + far_plane, |
| 298 | + }; |
| 299 | + |
| 300 | + encoder.update_constant_buffer(&self.bundle_render_cubemap.data.locals, &locals); |
| 301 | + encoder |
| 302 | + .update_buffer(&self.bundle_render_cubemap.data.matrices, &matrices, 0) |
| 303 | + .unwrap(); |
| 304 | + } |
| 305 | + |
| 306 | + encoder.clear_depth(&self.bundle_render_cubemap.data.out_depth, 1.0); |
| 307 | + self.bundle_render_cubemap.encode(encoder); |
| 308 | + |
| 309 | + // Display the render target as a skybox |
| 310 | + { |
| 311 | + // Update camera position |
| 312 | + let elapsed = self.start_time.elapsed(); |
| 313 | + let time = (elapsed.as_secs() as f32 + elapsed.subsec_nanos() as f32 / 1000_000_000.0) * |
| 314 | + 0.75; |
| 315 | + let x = time.sin(); |
| 316 | + let z = time.cos(); |
| 317 | + |
| 318 | + let view = Matrix4::look_at( |
| 319 | + Point3::new(x, x / 2.0, z), |
| 320 | + Point3::new(0.0, 0.0, 0.0), |
| 321 | + Vector3::unit_y(), |
| 322 | + ); |
| 323 | + |
| 324 | + let locals = Locals { |
| 325 | + inv_proj: self.projection.invert().unwrap().into(), |
| 326 | + view: view.into(), |
| 327 | + }; |
| 328 | + encoder.update_constant_buffer(&self.bundle.data.locals, &locals); |
| 329 | + } |
| 330 | + } |
| 331 | + |
| 332 | + fn on_resize(&mut self, window_targets: gfx_app::WindowTargets<R>) { |
| 333 | + self.bundle.data.out = window_targets.color; |
| 334 | + self.projection = |
| 335 | + cgmath::perspective(Deg(90.0f32), window_targets.aspect_ratio, 0.01, 100.0); |
| 336 | + |
| 337 | + self.proj_render = cgmath::perspective( |
| 338 | + cgmath::Deg(90.0), |
| 339 | + window_targets.aspect_ratio, |
| 340 | + 0.1, |
| 341 | + self.far_plane, |
| 342 | + ); |
| 343 | + } |
| 344 | +} |
| 345 | + |
| 346 | +pub fn main() { |
| 347 | + use gfx_app::Application; |
| 348 | + App::launch_simple("Render target example"); |
| 349 | +} |
0 commit comments