Rust glium Tessellation (2) 2D quad
glium テッセレーション
David Wolff著「OpenGL 4.0 シェーディング言語 ( OpenGL 4.0 Shading
Language Cookbook )」
第6章「ジオメトリシェーダとテッセレーションシェーダ」
「2D四角形をテッセレートする」
実行結果
tessellation level = 2
tessellation level = 4
tessellation level = 8
(Innerレベルは4に固定し、Outerレベルを変えている)
四角形の内部の点Pは、四角形の4隅(p0, p1, p2, p3)を制御点として、
次の補間式で表せる。u, vはパラメータで、0〜1の値をとる。
P = p0 * (1-u) * (1-v) + p1 * u * (1-v) + p2 * u * v + p3 * v * (1-u) 制御点:p0 = [-0.8, -0.8], p1 = [ 0.8, -0.8], p2 = [ 0.8, 0.8], p3 = [-0.8, 0.8]
この制御点をパッチ プリミティブとして、テッセレーションを使って、
レベルに対応したu, vを生成し描画する。
1 制御点(コントールポイント)の設定
let vertex_buffer = { #[derive(Copy, Clone)] struct Vertex { position: [f32; 2], } implement_vertex!(Vertex, position); glium::VertexBuffer::new(&display, &[ Vertex { position: [-0.8, -0.8] }, Vertex { position: [ 0.8, -0.8] }, Vertex { position: [ 0.8, 0.8] }, Vertex { position: [-0.8, 0.8] }, ] ).unwrap() };
(内容は、前例と同様)
2 パッチ プリミティブとパッチあたりの頂点数を設定
let indices = glium::index::NoIndices( PrimitiveType::Patches { vertices_per_patch: 4 });
(内容は、前例と同様)
3 シェーダプログラムの設定
let program = glium::Program::new(&display, glium::program::SourceCode { vertex_shader: " #version 140 in vec2 position; void main() { gl_Position = vec4(position, 0.0, 1.0); } ", tessellation_control_shader: Some(" #version 400 layout(vertices = 4) out; uniform int Outer = 5; uniform int Inner; void main() { gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position; gl_TessLevelOuter[0] = Outer; gl_TessLevelOuter[1] = Outer; gl_TessLevelOuter[2] = Outer; gl_TessLevelOuter[3] = Outer; gl_TessLevelInner[0] = Inner; gl_TessLevelInner[1] = Inner; } "), tessellation_evaluation_shader: Some(" #version 400 layout(quads, equal_spacing, ccw) in; void main() { float u = gl_TessCoord.x; float v = gl_TessCoord.y; vec4 p0 = gl_in[0].gl_Position; vec4 p1 = gl_in[1].gl_Position; vec4 p2 = gl_in[2].gl_Position; vec4 p3 = gl_in[3].gl_Position; gl_Position = p0 * (1-u) * (1-v) + p1 * u * (1-v) + p2 * u * v + p3 * v * (1-u); } "), geometry_shader: Some(" #version 400 layout(triangles) in; layout(triangle_strip, max_vertices = 3) out; out vec3 color; void main() { gl_Position = gl_in[0].gl_Position; color = vec3(1.0, 0.0, 0.0); EmitVertex(); gl_Position = gl_in[1].gl_Position; color = vec3(1.0, 1.0, 0.0); EmitVertex(); gl_Position = gl_in[2].gl_Position; color = vec3(0.0, 0.0, 1.0); EmitVertex(); EndPrimitive(); } "), fragment_shader: " #version 140 in vec3 color; out vec4 f_color; void main() { f_color = vec4(color, 1.0); } ", }).unwrap();
この例ではジオメトリシェーダを使う。ジオメトリシェーダの設定にはOptionを
使うので、Some()で設定する。
テッセレーション座標u, vは、テッセレーション評価シェーダで、
u = gl_TessCoord.x v = gl_TessCoord.y
の式で生成される。
Rust glium Tessellation (1) Bezier Curve
glium(https://github.com/tomaka/glium)のexamplesにあるtessellation
プログラム(tessellation.rs)を参考にして、David Wolff著「OpenGL 4.0
シェーディング言語 ( OpenGL 4.0 Shading Language Cookbook )」の6章
「ジオメトリシェーダとテッセレーションシェーダ」をgliumで書いてみました。
今回は、「曲線をテッセレートする」の項です。テッセレーションの方法で、
曲線を描きます。
実行結果
tessellation level = 3
tessellation level = 5
tessellation level = 8
この例では、曲線の描画に3次べジェ曲線(ブレンド関数はベルンシュタイン
多項式)を使うので、4個の制御点(コントロールポイント)が必要です。
この4個の制御点がパッチ プリミティブになります。
1 コントロールポイントの設定
let vertex_buffer = { #[derive(Copy, Clone)] struct Vertex { position: [f32; 2], } implement_vertex!(Vertex, position); glium::VertexBuffer::new(&display, &[ Vertex { position: [-0.8, -0.8] }, Vertex { position: [-0.4, 0.8] }, Vertex { position: [ 0.4, -0.8] }, Vertex { position: [ 0.8, 0.8] }, ] ).unwrap() };
VertexBufferを使ってコントロールポイントの頂点座標を設定します。
2 パッチ プリミティブとパッチあたりの頂点数を設定
let indices = glium::index::NoIndices( PrimitiveType::Patches { vertices_per_patch: 4 });
IndexBufferのPrimitiveTypeとvertices_per_patchで、パッチ プリミティブの
使用とパッチあたりの頂点数を設定します。
3 シェーダプログラムの設定
let program = glium::Program::new(&display, glium::program::SourceCode { vertex_shader: " #version 140 in vec2 position; void main() { gl_Position = vec4(position, 0.0, 1.0); } ", tessellation_control_shader: Some(" #version 400 layout(vertices = 4) out; uniform int tess_level = 5; void main() { gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position; gl_TessLevelOuter[0] = 1; gl_TessLevelOuter[1] = tess_level; } "), tessellation_evaluation_shader: Some(" #version 400 layout(isolines) in; void main() { float u = gl_TessCoord.x; vec3 p0 = gl_in[0].gl_Position.xyz; vec3 p1 = gl_in[1].gl_Position.xyz; vec3 p2 = gl_in[2].gl_Position.xyz; vec3 p3 = gl_in[3].gl_Position.xyz; float u1 = (1.0 - u); float u2 = u * u; float b3 = u2 * u; float b2 = 3.0 * u2 * u1; float b1 = 3.0 * u * u1 * u1; float b0 = u1 * u1 * u1; vec3 p = p0 * b0 + p1 * b1 + p2 * b2 + p3 * b3; gl_Position = vec4(p, 1.0); } "), geometry_shader: None, fragment_shader: " #version 140 out vec4 f_color; void main() { f_color = vec4(1.0, 1.0, 1.0, 1.0); } ", }).unwrap();
このプログラムでは、バーテックスシェーダ、テッセレーション制御シェーダ、
テッセレーション評価シェーダを使用します。このような場合は、Programの
SourceCodeを使って設定します。
テッセレーションシェーダとジオメトリシェーダはOptionとして設定するので、
None(使用しない)かSome()(使用する場合)で設定します。
曲線の描画では、Innerレベルは使用しません。Outerレベルでは、Outer[0]を1、
Outer[1]にレベルを設定します。GPUによっては、入れ替えが必要な場合が
あります。
Rust glium ( OpenGL ) triangle and square
rust の glium ライブラリを利用して、三角と四角を同一ウィンドウに
表示します。
実行結果
プログラム
#[macro_use] extern crate glium; fn main() { use glium::{DisplayBuild, Surface}; let display = glium::glutin::WindowBuilder::new() .with_dimensions(800, 600) .with_title(format!("Glium Triangle and Square")) .build_glium().unwrap(); #[derive(Copy, Clone)] struct Vertex { position: [f32; 2], } implement_vertex!(Vertex, position); // triangle let vertex1 = Vertex { position: [-0.75, -0.5] }; let vertex2 = Vertex { position: [-0.5 , 0.5] }; let vertex3 = Vertex { position: [-0.25, -0.5] }; let shape1 = vec![vertex1, vertex2, vertex3]; let vertex_buffer1 = glium::VertexBuffer::new(&display, &shape1).unwrap(); let indices1 = glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList); //square let vertex1 = Vertex { position: [ 0.25, -0.5] }; let vertex2 = Vertex { position: [ 0.25, 0.5] }; let vertex3 = Vertex { position: [ 0.75, 0.5] }; let vertex4 = Vertex { position: [ 0.75, -0.5] }; let shape2 = vec![vertex1, vertex2, vertex3, vertex4]; let vertex_buffer2 = glium::VertexBuffer::new(&display, &shape2).unwrap(); let indices2 = glium::IndexBuffer::new(&display, glium::index::PrimitiveType::TrianglesList, &[0u16, 1, 2, 2, 0, 3,]).unwrap(); let vertex_shader_src = r#" #version 140 in vec2 position; void main() { gl_Position = vec4(position, 0.0, 1.0); } "#; let fragment_shader_src = r#" #version 140 out vec4 color; void main() { color = vec4(1.0, 0.0, 0.0, 1.0); } "#; let program = glium::Program::from_source(&display, vertex_shader_src, fragment_shader_src, None).unwrap(); loop { let mut target = display.draw(); target.clear_color(0.0, 0.0, 1.0, 1.0); // triangle target.draw(&vertex_buffer1, &indices1, &program, &glium::uniforms::EmptyUniforms, &Default::default()).unwrap(); // square target.draw(&vertex_buffer2, &indices2, &program, &glium::uniforms::EmptyUniforms, &Default::default()).unwrap(); target.finish().unwrap(); for ev in display.poll_events() { match ev { glium::glutin::Event::Closed => return, _ => () } } } }
Cargo.toml
[package] name = "triangle" version = "0.1.0" authors = ["xxxxx"] [dependencies] glium = "*"
vertex, VertexBuffer, IndexBufferの設定
三角形と四角形のvertex, VertexBuffer, IndexBufferをそれぞれ準備します。
IndexBufferの設定では、三角形では頂点indexを使用しないのでNoIndicesを
使います。
四角形では頂点indexを使用しているので、IndexBufferを使います。
描画
target.draw()文を2回使って、三角形と四角形を描画します。
Rust OpenGL gliumライブラリ
今回は、RustでOpenGLを扱うライブラリの一つであるgliumについて
まとめています。(glium([https://github.com/tomaka/glium/)の
examplesにあるtutorial-02.rsを使用しています。)
gliumでは、OpenGLのAPIとは異なる独自のAPIを導入しています。
以下は、gliumでOpenGLを描画する際必要となる文です。
1 windowとOpenGL contextの準備
use glium::{DisplayBuild, Surface}; let display = glium::glutin::WindowBuilder::new() .with_dimensions(800, 600) .with_title(format!("Glium Triangle Test")) .build_glium().unwrap();
window操作のライブラリとして、glutinを利用しています。
この文は、windowとOpenGL contextを生成します。その際、windowサイズ、
windowタイトルも設定しています。
2 vertexの設定
#[derive(Copy, Clone)] struct Vertex { position: [f32; 2], } implement_vertex!(Vertex, position); let vertex1 = Vertex { position: [-0.5, -0.5] }; let vertex2 = Vertex { position: [ 0.0, 0.5] }; let vertex3 = Vertex { position: [ 0.5, -0.5] }; let shape = vec![vertex1, vertex2, vertex3];
#[derive]は継承のアトリビュートです。Vertex structureは、Copy, Clone
トレイトの機能を継承することになります。
頂点座標は、Vertex structureのベクトルとして設定します。
3 VertexBufferの設定
let vertex_buffer = glium::VertexBuffer::new(&display, &shape).unwrap();
頂点座標を、VertexBufferに設定します。
4 IndexBufferの設定
let indices = glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList);
IndexBufferの設定に相当する文です。
この例では、indexを使用しません。このような場合は、primitive typeを
設定するため、NoIndicesを使います。
5 shaderの設定
let vertex_shader_src = r#" #version 140 in vec2 position; void main() { gl_Position = vec4(position, 0.0, 1.0); } "#; let fragment_shader_src = r#" #version 140 out vec4 color; void main() { color = vec4(1.0, 0.0, 0.0, 1.0); } "#;
6 shderのリンク
let program = glium::Program::from_source(&display, vertex_shader_src, fragment_shader_src, None).unwrap();
shaderプログラムのリンクには、Program文を使用します。
最後の引数Noneは、geometry shaderを使用しないことを示しています。
7 windowのクリア、描画、終了
let mut target = display.draw(); target.clear_color(0.0, 0.0, 1.0, 1.0); target.draw(&vertex_buffer, &indices, &program, &glium::uniforms::EmptyUniforms, &Default::default()).unwrap(); target.finish().unwrap();
display.draw()で、描画用フレームバッファ(バックバッファ)を生成します。
target.draw()で、フレームバッファに描画します。その際、VertexBuffer, IndexBuffer,
Programを設定します。
この例では、uniform変数を使用していないので、EmptyUniformsを設定しています。
また、depth、stencil等の描画パラメータも使用していないので、DrawParametersの
設定にはDefaule::default()を設定しています。
target.finish()で、フロントバッファに描画します。
8 windowのクローズ
for ev in display.poll_events() { match ev { glium::glutin::Event::Closed => return, _ => () } }
display.poll_events()で、ウィンドウのイベントリストを生成します。
「glium::glutin::Event::Closed => return」文で、ウィンドウのClosedイベントを
検出するとreturn文を用いて、ループ(loop{})を抜けるようにしています。
Rust glium テッセレーション ( Tessellation )
glium (https://github.com/tomaka/glium)のexamplesに、tessellationの
サンプル(tessellation.rs)があります。
上矢印キーと下矢印キーを使って、tessellation レベルを上げ下げできます。
実行結果
tessellation level = 2
tessellation level = 4
tessellation level = 8
(Inner-levelとOuter-levelは同じ値にしています。)
ビルドと実行
gliumフォルダで
$ cargo run --example tessellation
を実行します。
Rust ImGui + Glium ( OpenGL )
ImGui のGUI(ボタン)から、Gliumで描画したtriangleの回転角をコントロールできる
ようにしています。
(実行結果)
・ imgui ウィンドウ上の「+」ボタンと「ー」ボタンを押すと、回転角の値が増減します。
プログラム
### imgui-glium.rs
#[macro_use] extern crate glium; #[macro_use] extern crate imgui; use glium::glutin; use glium::glutin::{ElementState, Event, MouseButton, MouseScrollDelta, TouchPhase}; use glium::{DisplayBuild, Surface}; use imgui::{ImGui, ImGuiSetCond_FirstUseEver}; use imgui::glium_renderer::Renderer; use std::time::Instant; fn main() { let display = glutin::WindowBuilder::new() .with_dimensions(600, 600) .with_title(format!("ImGui Glium Test")) .build_glium().unwrap(); let mut imgui = ImGui::init(); let mut renderer = Renderer::init(&mut imgui, &display).unwrap(); let mut last_frame = Instant::now(); let mut mouse_pos = (0, 0); let mut mouse_pressed = (false, false, false); let mut mouse_wheel = 0.0; #[derive(Copy, Clone)] struct Vertex { position: [f32; 2], } implement_vertex!(Vertex, position); let vertex1 = Vertex { position: [-0.5, -0.5] }; let vertex2 = Vertex { position: [ 0.0, 0.5] }; let vertex3 = Vertex { position: [ 0.5, -0.5] }; let shape = vec![vertex1, vertex2, vertex3]; let vertex_buffer = glium::VertexBuffer::new(&display, &shape).unwrap(); let indices = glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList); let vertex_shader_src = r#" #version 140 in vec2 position; uniform mat4 MVP; void main() { gl_Position = MVP * vec4(position, 0.0, 1.0); } "#; let fragment_shader_src = r#" #version 140 out vec4 color; void main() { color = vec4(1.0, 0.0, 0.0, 1.0); } "#; let program = glium::Program::from_source(&display, vertex_shader_src, fragment_shader_src, None).unwrap(); let mut t: f32 = 0.0; loop { let mut target = display.draw(); target.clear_color(0.2, 0.2, 0.2, 1.0); let uniform = uniform! { MVP: [ [ t.cos(), t.sin(), 0.0, 0.0], [-t.sin(), t.cos(), 0.0, 0.0], [ 0.0, 0.0, 1.0, 0.0], [ 0.0, 0.0, 0.0, 1.0f32], ], }; target.draw(&vertex_buffer, &indices, &program, &uniform, &Default::default()).unwrap(); let now = Instant::now(); let delta = now - last_frame; let delta_s = delta.as_secs() as f32 + delta.subsec_nanos() as f32 / 1_000_000_000.0; last_frame = now; let scale = imgui.display_framebuffer_scale(); imgui.set_mouse_pos(mouse_pos.0 as f32 / scale.0, mouse_pos.1 as f32 / scale.1); imgui.set_mouse_down(&[mouse_pressed.0, mouse_pressed.1, mouse_pressed.2, false, false]); imgui.set_mouse_wheel(mouse_wheel / scale.1); mouse_wheel = 0.0; let window = display.get_window().unwrap(); let size_points = window.get_inner_size_points().unwrap(); let size_pixels = window.get_inner_size_pixels().unwrap(); let ui = imgui.frame(size_points, size_pixels, delta_s); // imgui ui ui.window(im_str!("Triangle")) .position((10.0, 10.0), ImGuiSetCond_FirstUseEver) .size((200.0, 100.0), ImGuiSetCond_FirstUseEver) .build(|| { ui.text(im_str!("rotation")); ui.separator(); if ui.small_button(im_str!("+")) { t += 0.02; } if ui.small_button(im_str!("-")) { t -= 0.02; } ui.text(im_str!("rotation angle: {:.2} rad", t)); }); renderer.render(&mut target, ui).unwrap(); target.finish().unwrap(); for event in display.poll_events() { match event { Event::Closed => return, Event::MouseMoved(x, y) => mouse_pos = (x, y), Event::MouseInput(state, MouseButton::Left) => mouse_pressed.0 = state == ElementState::Pressed, Event::MouseInput(state, MouseButton::Right) => mouse_pressed.1 = state == ElementState::Pressed, Event::MouseInput(state, MouseButton::Middle) => mouse_pressed.2 = state == ElementState::Pressed, Event::MouseWheel(MouseScrollDelta::LineDelta(_, y), TouchPhase::Moved) => mouse_wheel = y, Event::MouseWheel(MouseScrollDelta::PixelDelta(_, y), TouchPhase::Moved) => mouse_wheel = y, _ => () } } } }
### Cargo.toml
[package] name = "test1" version = "0.1.0" authors = ["xxxxx"] [dependencies] glium = "*" imgui = "*" image = "*"
Rust Glium CubeMap ( OpenGL )
CubeMap
(実行結果)
・ cubemap 画像は、Humus サイト(http://www.humus.name/)のTexures(Yokohama 3)
を使用しています。(画像サイズを512x512にしています。)
プログラム
###glium-cubemap.rs
#[macro_use] extern crate glium; extern crate image; use std::io::Cursor; use glium::{DisplayBuild, Surface}; use glium::glutin; use glium::index::PrimitiveType; mod camera; fn main() { let display = glutin::WindowBuilder::new() .with_vsync() .with_depth_buffer(24) .with_dimensions(800, 600) .with_title(format!("Glium CubeMap")) .build_glium() .unwrap(); let image = image::load(Cursor::new(&include_bytes!("images/posx512.jpg")[..]), image::JPEG).unwrap().to_rgba(); let image_dimensions = image.dimensions(); let image = glium::texture::RawImage2d::from_raw_rgba_reversed(image.into_raw(), image_dimensions); let tex_posx = glium::Texture2d::new(&display, image).unwrap(); let image = image::load(Cursor::new(&include_bytes!("images/negx512.jpg")[..]), image::JPEG).unwrap().to_rgba(); let image_dimensions = image.dimensions(); let image = glium::texture::RawImage2d::from_raw_rgba_reversed(image.into_raw(), image_dimensions); let tex_negx = glium::Texture2d::new(&display, image).unwrap(); let image = image::load(Cursor::new(&include_bytes!("images/posy512.jpg")[..]), image::JPEG).unwrap().to_rgba(); let image_dimensions = image.dimensions(); let image = glium::texture::RawImage2d::from_raw_rgba_reversed(image.into_raw(), image_dimensions); let tex_posy = glium::Texture2d::new(&display, image).unwrap(); let image = image::load(Cursor::new(&include_bytes!("images/negy512.jpg")[..]), image::JPEG).unwrap().to_rgba(); let image_dimensions = image.dimensions(); let image = glium::texture::RawImage2d::from_raw_rgba_reversed(image.into_raw(), image_dimensions); let tex_negy = glium::Texture2d::new(&display, image).unwrap(); let image = image::load(Cursor::new(&include_bytes!("images/posz512.jpg")[..]), image::JPEG).unwrap().to_rgba(); let image_dimensions = image.dimensions(); let image = glium::texture::RawImage2d::from_raw_rgba_reversed(image.into_raw(), image_dimensions); let tex_posz = glium::Texture2d::new(&display, image).unwrap(); let image = image::load(Cursor::new(&include_bytes!("images/negz512.jpg")[..]), image::JPEG).unwrap().to_rgba(); let image_dimensions = image.dimensions(); let image = glium::texture::RawImage2d::from_raw_rgba_reversed(image.into_raw(), image_dimensions); let tex_negz = glium::Texture2d::new(&display, image).unwrap(); let cubemap = glium::texture::Cubemap::empty(&display, 512).unwrap(); // skybox let skybox_vertex_buffer = { #[derive(Copy, Clone)] struct Vertex { position: [f32; 3], } implement_vertex!(Vertex, position); let side2: f32 = 50.0 / 2.0; glium::VertexBuffer::new(&display, &[ // Front Vertex { position: [-side2, -side2, side2] }, Vertex { position: [ side2, -side2, side2] }, Vertex { position: [ side2, side2, side2] }, Vertex { position: [-side2, side2, side2] }, // Right Vertex { position: [ side2, -side2, side2] }, Vertex { position: [ side2, -side2, -side2] }, Vertex { position: [ side2, side2, -side2] }, Vertex { position: [ side2, side2, side2] }, // Back Vertex { position: [-side2, -side2, -side2] }, Vertex { position: [-side2, side2, -side2] }, Vertex { position: [ side2, side2, -side2] }, Vertex { position: [ side2, -side2, -side2] }, // Left Vertex { position: [-side2, -side2, side2] }, Vertex { position: [-side2, side2, side2] }, Vertex { position: [-side2, side2, -side2] }, Vertex { position: [-side2, -side2, -side2] }, // Bottom Vertex { position: [-side2, -side2, side2] }, Vertex { position: [-side2, -side2, -side2] }, Vertex { position: [ side2, -side2, -side2] }, Vertex { position: [ side2, -side2, side2] }, // Top Vertex { position: [-side2, side2, side2] }, Vertex { position: [ side2, side2, side2] }, Vertex { position: [ side2, side2, -side2] }, Vertex { position: [-side2, side2, -side2] }, ] ).unwrap() }; let skybox_index_buffer = glium::IndexBuffer::new(&display, glium::index::PrimitiveType::TrianglesList, &[ // Front 0u16, 2, 1, 0, 3, 2, // Right 4, 6, 5, 4, 7, 6, // Back 8, 10, 9, 8, 11, 10, // Left 12, 14, 13, 12, 15, 14, // Bottom 16, 18, 17, 16, 19, 18, // Top 20, 22, 21, 20, 23, 22, ]).unwrap(); let skybox_program = glium::Program::from_source(&display, " #version 140 in vec3 position; out vec3 ReflectDir; uniform mat4 model; uniform mat4 view; uniform mat4 perspective; void main() { ReflectDir = position; gl_Position = perspective * view * model * vec4(position, 1.0); } ", " #version 140 in vec3 ReflectDir; out vec4 color; uniform samplerCube cubetex; void main() { color = texture(cubetex, ReflectDir); } ", None).unwrap(); //model let model_vertex_buffer = { #[derive(Copy, Clone)] struct Vertex { position: [f32; 3], normal: [f32; 3], } implement_vertex!(Vertex, position, normal); let side2: f32 = 2.0 / 2.0; glium::VertexBuffer::new(&display, &[ // Front Vertex { position: [-side2, -side2, side2], normal: [ 0.0, 0.0, 1.0] }, Vertex { position: [ side2, -side2, side2], normal: [ 0.0, 0.0, 1.0] }, Vertex { position: [ side2, side2, side2], normal: [ 0.0, 0.0, 1.0] }, Vertex { position: [-side2, side2, side2], normal: [ 0.0, 0.0, 1.0] }, // Right Vertex { position: [ side2, -side2, side2], normal: [ 1.0, 0.0, 0.0] }, Vertex { position: [ side2, -side2, -side2], normal: [ 1.0, 0.0, 0.0] }, Vertex { position: [ side2, side2, -side2], normal: [ 1.0, 0.0, 0.0] }, Vertex { position: [ side2, side2, side2], normal: [ 1.0, 0.0, 0.0] }, // Back Vertex { position: [-side2, -side2, -side2], normal: [ 0.0, 0.0, -1.0] }, Vertex { position: [-side2, side2, -side2], normal: [ 0.0, 0.0, -1.0] }, Vertex { position: [ side2, side2, -side2], normal: [ 0.0, 0.0, -1.0] }, Vertex { position: [ side2, -side2, -side2], normal: [ 0.0, 0.0, -1.0] }, // Left Vertex { position: [-side2, -side2, side2], normal: [-1.0, 0.0, 0.0] }, Vertex { position: [-side2, side2, side2], normal: [-1.0, 0.0, 0.0] }, Vertex { position: [-side2, side2, -side2], normal: [-1.0, 0.0, 0.0] }, Vertex { position: [-side2, -side2, -side2], normal: [-1.0, 0.0, 0.0] }, // Bottom Vertex { position: [-side2, -side2, side2], normal: [ 0.0, -1.0, 0.0] }, Vertex { position: [-side2, -side2, -side2], normal: [ 0.0, -1.0, 0.0] }, Vertex { position: [ side2, -side2, -side2], normal: [ 0.0, -1.0, 0.0] }, Vertex { position: [ side2, -side2, side2], normal: [ 0.0, -1.0, 0.0] }, // Top Vertex { position: [-side2, side2, side2], normal: [ 0.0, 1.0, 0.0] }, Vertex { position: [ side2, side2, side2], normal: [ 0.0, 1.0, 0.0] }, Vertex { position: [ side2, side2, -side2], normal: [ 0.0, 1.0, 0.0] }, Vertex { position: [-side2, side2, -side2], normal: [ 0.0, 1.0, 0.0] }, ] ).unwrap() }; let model_index_buffer = glium::IndexBuffer::new(&display, glium::index::PrimitiveType::TrianglesList, &[ // Front 0u16, 2, 1, 0, 3, 2, // Right 4, 6, 5, 4, 7, 6, // Back 8, 10, 9, 8, 11, 10, // Left 12, 14, 13, 12, 15, 14, // Bottom 16, 18, 17, 16, 19, 18, // Top 20, 22, 21, 20, 23, 22, ]).unwrap(); let model_program = glium::Program::from_source(&display, " #version 140 in vec3 position; in vec3 normal; out vec4 v_position; out vec3 v_normal; uniform mat4 model; uniform mat4 view; uniform mat4 perspective; void main() { mat4 modelviewMatrix = view * model; mat3 normalMatrix = mat3(modelviewMatrix); v_position = modelviewMatrix * vec4(position, 1.0); v_normal = normalMatrix * normal; gl_Position = perspective * v_position; } ", " #version 140 in vec4 v_position; in vec3 v_normal; out vec4 f_color; uniform samplerCube cubetex; uniform float ReflectFactor; uniform vec4 MaterialColor; uniform vec3 WorldCameraPosition; void main() { vec3 s = normalize(v_normal); vec3 v = normalize(WorldCameraPosition - v_position.xyz); vec3 ReflectDir = reflect(v, s); vec4 cubeMapColor = texture(cubetex, ReflectDir); f_color = mix(MaterialColor, cubeMapColor, ReflectFactor); } ", None).unwrap(); let dest_rect1 = glium::BlitTarget { left: 0, bottom: 0, width: 512, height: 512, }; let mut camera = camera::CameraState::new(); let scale: f32 = 1.0; let scale2: f32 = 1.0; let mut t: f32 = 0.0; // main loop loop { t += 0.002; let framebuffer1 = glium::framebuffer::SimpleFrameBuffer::new(&display, cubemap.main_level().image(glium::texture::CubeLayer::PositiveX)).unwrap(); let framebuffer2 = glium::framebuffer::SimpleFrameBuffer::new(&display, cubemap.main_level().image(glium::texture::CubeLayer::NegativeX)).unwrap(); let framebuffer3 = glium::framebuffer::SimpleFrameBuffer::new(&display, cubemap.main_level().image(glium::texture::CubeLayer::PositiveY)).unwrap(); let framebuffer4 = glium::framebuffer::SimpleFrameBuffer::new(&display, cubemap.main_level().image(glium::texture::CubeLayer::NegativeY)).unwrap(); let framebuffer5 = glium::framebuffer::SimpleFrameBuffer::new(&display, cubemap.main_level().image(glium::texture::CubeLayer::PositiveZ)).unwrap(); let framebuffer6 = glium::framebuffer::SimpleFrameBuffer::new(&display, cubemap.main_level().image(glium::texture::CubeLayer::NegativeZ)).unwrap(); tex_posx.as_surface().blit_whole_color_to(&framebuffer1, &dest_rect1, glium::uniforms::MagnifySamplerFilter::Linear); tex_negx.as_surface().blit_whole_color_to(&framebuffer2, &dest_rect1, glium::uniforms::MagnifySamplerFilter::Linear); tex_negy.as_surface().blit_whole_color_to(&framebuffer3, &dest_rect1, glium::uniforms::MagnifySamplerFilter::Linear); tex_posy.as_surface().blit_whole_color_to(&framebuffer4, &dest_rect1, glium::uniforms::MagnifySamplerFilter::Linear); tex_posz.as_surface().blit_whole_color_to(&framebuffer5, &dest_rect1, glium::uniforms::MagnifySamplerFilter::Linear); tex_negz.as_surface().blit_whole_color_to(&framebuffer6, &dest_rect1, glium::uniforms::MagnifySamplerFilter::Linear); let mut target = display.draw(); target.clear_color_and_depth((0.0, 0.0, 1.0, 1.0), 1.0); let model = [ [ t.cos()*scale, 0.0 , t.sin()*scale, 0.0], [ 0.0 , 1.0*scale, 0.0, 0.0], [-t.sin()*scale, 0.0 , t.cos()*scale, 0.0], [ 0.0, 0.0 , 0.0, 1.0f32], ]; let camera_position: [f32; 3]= [0.0, 0.0, -8.0]; camera.set_position((0.0, 0.0, -8.0)); camera.set_direction((0.0, 0.0, 1.0)); let view = camera.get_view(); let perspective = camera.get_perspective(); let material_color: [f32; 4] = [0.9, 0.9, 0.9, 1.0]; let reflect_factor: f32 = 0.9; let skybox_uniforms = uniform! { model: model, view: view, perspective: perspective, cubetex: cubemap.sampled().magnify_filter(glium::uniforms::MagnifySamplerFilter::Linear), }; let model_uniforms = uniform! { model: [ [ t.cos()*scale2, 0.0 , t.sin()*scale2, 0.0], [ 0.0, 1.0*scale2, 0.0, 0.0], [-t.sin()*scale2, 0.0 , t.cos()*scale2, 0.0], [ 0.0, 0.0 , 0.0, 1.0f32] ], view: view, perspective: perspective, cubetex: cubemap.sampled().magnify_filter(glium::uniforms::MagnifySamplerFilter::Linear), ReflectFactor: reflect_factor, MaterialColor: material_color, WorldCameraPosition: camera_position, }; let params = glium::DrawParameters { depth: glium::Depth { test: glium::draw_parameters::DepthTest::IfLess, write: true, .. Default::default() }, .. Default::default() }; target.draw(&skybox_vertex_buffer, &skybox_index_buffer, &skybox_program, &skybox_uniforms, ¶ms).unwrap(); target.draw(&model_vertex_buffer, &model_index_buffer, &model_program, &model_uniforms, ¶ms).unwrap(); target.finish().unwrap(); for event in display.poll_events() { match event { glutin::Event::Closed => return, _ => () } } } }
### camera.rs
glium ソース内のexamples/supportのcamera.rsを使用。
###Cargo.toml
[package] name = "cubemap" version = "0.1.0" authors = ["xxxxx"] [dependencies] glium = "*" image = "*" glutin = "*"