MethaneKit
257 строк · 10.7 Кб
1/******************************************************************************
2
3Copyright 2019 Evgeny Gorodetskiy
4
5Licensed under the Apache License, Version 2.0 (the "License"),
6you may not use this file except in compliance with the License.
7You may obtain a copy of the License at
8
9http://www.apache.org/licenses/LICENSE-2.0
10
11Unless required by applicable law or agreed to in writing, software
12distributed under the License is distributed on an "AS IS" BASIS,
13WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14See the License for the specific language governing permissions and
15limitations under the License.
16
17*******************************************************************************
18
19FILE: TexturedCubeApp.cpp
20Tutorial demonstrating textured cube rendering with Methane graphics API
21
22******************************************************************************/
23
24#include "TexturedCubeApp.h"
25
26#include <Methane/Tutorials/AppSettings.h>
27#include <Methane/Graphics/CubeMesh.hpp>
28#include <Methane/Graphics/TypeConverters.hpp>
29#include <Methane/Data/TimeAnimation.h>
30
31namespace Methane::Tutorials
32{
33
34struct CubeVertex
35{
36gfx::Mesh::Position position;
37gfx::Mesh::Normal normal;
38gfx::Mesh::TexCoord texcoord;
39
40inline static const gfx::Mesh::VertexLayout layout{
41gfx::Mesh::VertexField::Position,
42gfx::Mesh::VertexField::Normal,
43gfx::Mesh::VertexField::TexCoord,
44};
45};
46
47TexturedCubeApp::TexturedCubeApp()
48: UserInterfaceApp(
49GetGraphicsTutorialAppSettings("Methane Textured Cube", AppOptions::GetDefaultWithColorOnlyAndAnim()),
50GetUserInterfaceTutorialAppSettings(AppOptions::GetDefaultWithColorOnlyAndAnim()),
51"Methane tutorial of textured cube rendering")
52{
53m_shader_uniforms.light_position = hlslpp::float3(0.F, 20.F, -25.F);
54m_camera.ResetOrientation({ { 13.0F, 13.0F, -13.0F }, { 0.0F, 0.0F, 0.0F }, { 0.0F, 1.0F, 0.0F } });
55
56m_shader_uniforms.model_matrix = hlslpp::float4x4::scale(m_cube_scale);
57
58// Setup animations
59GetAnimations().emplace_back(std::make_shared<Data::TimeAnimation>(std::bind(&TexturedCubeApp::Animate, this, std::placeholders::_1, std::placeholders::_2)));
60}
61
62TexturedCubeApp::~TexturedCubeApp()
63{
64// Wait for GPU rendering is completed to release resources
65WaitForRenderComplete();
66}
67
68void TexturedCubeApp::Init()
69{
70UserInterfaceApp::Init();
71
72const rhi::CommandQueue render_cmd_queue = GetRenderContext().GetRenderCommandKit().GetQueue();
73m_camera.Resize(GetRenderContext().GetSettings().frame_size);
74
75// Create vertex buffer for cube mesh
76const gfx::CubeMesh<CubeVertex> cube_mesh(CubeVertex::layout);
77const Data::Size vertex_data_size = cube_mesh.GetVertexDataSize();
78const Data::Size vertex_size = cube_mesh.GetVertexSize();
79rhi::Buffer vertex_buffer = GetRenderContext().CreateBuffer(rhi::BufferSettings::ForVertexBuffer(vertex_data_size, vertex_size));
80vertex_buffer.SetName("Cube Vertex Buffer");
81vertex_buffer.SetData(render_cmd_queue, {
82reinterpret_cast<Data::ConstRawPtr>(cube_mesh.GetVertices().data()), // NOSONAR
83vertex_data_size
84});
85m_vertex_buffer_set = rhi::BufferSet(rhi::BufferType::Vertex, { vertex_buffer });
86
87// Create index buffer for cube mesh
88const Data::Size index_data_size = cube_mesh.GetIndexDataSize();
89const gfx::PixelFormat index_format = gfx::GetIndexFormat(cube_mesh.GetIndex(0));
90m_index_buffer = GetRenderContext().CreateBuffer(rhi::BufferSettings::ForIndexBuffer(index_data_size, index_format));
91m_index_buffer.SetName("Cube Index Buffer");
92m_index_buffer.SetData(render_cmd_queue, {
93reinterpret_cast<Data::ConstRawPtr>(cube_mesh.GetIndices().data()), // NOSONAR
94index_data_size
95});
96
97// Create constants buffer for frame rendering
98const auto constants_data_size = static_cast<Data::Size>(sizeof(m_shader_constants));
99m_const_buffer = GetRenderContext().CreateBuffer(rhi::BufferSettings::ForConstantBuffer(constants_data_size));
100m_const_buffer.SetName("Constants Buffer");
101m_const_buffer.SetData(render_cmd_queue, {
102reinterpret_cast<Data::ConstRawPtr>(&m_shader_constants), // NOSONAR
103constants_data_size
104});
105
106// Create render state with program
107m_render_state = GetRenderContext().CreateRenderState(
108rhi::RenderState::Settings
109{
110GetRenderContext().CreateProgram(
111rhi::Program::Settings
112{
113rhi::Program::ShaderSet
114{
115{ rhi::ShaderType::Vertex, { Data::ShaderProvider::Get(), { "TexturedCube", "CubeVS" } } },
116{ rhi::ShaderType::Pixel, { Data::ShaderProvider::Get(), { "TexturedCube", "CubePS" } } },
117},
118rhi::ProgramInputBufferLayouts
119{
120rhi::Program::InputBufferLayout
121{
122rhi::Program::InputBufferLayout::ArgumentSemantics { cube_mesh.GetVertexLayout().GetSemantics() }
123}
124},
125rhi::ProgramArgumentAccessors
126{
127{ { rhi::ShaderType::All, "g_uniforms" }, rhi::ProgramArgumentAccessor::Type::FrameConstant },
128{ { rhi::ShaderType::Pixel, "g_constants" }, rhi::ProgramArgumentAccessor::Type::Constant },
129{ { rhi::ShaderType::Pixel, "g_texture" }, rhi::ProgramArgumentAccessor::Type::Constant },
130{ { rhi::ShaderType::Pixel, "g_sampler" }, rhi::ProgramArgumentAccessor::Type::Constant },
131},
132GetScreenRenderPattern().GetAttachmentFormats()
133}
134),
135GetScreenRenderPattern()
136}
137);
138m_render_state.GetSettings().program_ptr->SetName("Textured Phong Lighting");
139m_render_state.SetName("Final FB Render Pipeline State");
140
141// Load texture image from file
142constexpr gfx::ImageOptionMask image_options({ gfx::ImageOption::Mipmapped, gfx::ImageOption::SrgbColorSpace });
143m_cube_texture = GetImageLoader().LoadImageToTexture2D(render_cmd_queue, "MethaneBubbles.jpg", image_options, "Cube Face Texture");
144
145// Create sampler for image texture
146m_texture_sampler = GetRenderContext().CreateSampler(
147rhi::Sampler::Settings
148{
149rhi::Sampler::Filter { rhi::Sampler::Filter::MinMag::Linear },
150rhi::Sampler::Address { rhi::Sampler::Address::Mode::ClampToEdge }
151}
152);
153
154// Create frame buffer resources
155const auto uniforms_data_size = static_cast<Data::Size>(sizeof(m_shader_uniforms));
156for(TexturedCubeFrame& frame : GetFrames())
157{
158// Create uniforms buffer with volatile parameters for frame rendering
159frame.uniforms_buffer = GetRenderContext().CreateBuffer(rhi::BufferSettings::ForConstantBuffer(uniforms_data_size, false, true));
160frame.uniforms_buffer.SetName(fmt::format("Uniforms Buffer {}", frame.index));
161
162// Configure program resource bindings
163frame.program_bindings = m_render_state.GetProgram().CreateBindings({
164{ { rhi::ShaderType::All, "g_uniforms" }, { { frame.uniforms_buffer.GetInterface() } } },
165{ { rhi::ShaderType::Pixel, "g_constants" }, { { m_const_buffer.GetInterface() } } },
166{ { rhi::ShaderType::Pixel, "g_texture" }, { { m_cube_texture.GetInterface() } } },
167{ { rhi::ShaderType::Pixel, "g_sampler" }, { { m_texture_sampler.GetInterface() } } },
168}, frame.index);
169frame.program_bindings.SetName(fmt::format("Cube Bindings {}", frame.index));
170
171// Create command list for rendering
172frame.render_cmd_list = render_cmd_queue.CreateRenderCommandList(frame.screen_pass);
173frame.render_cmd_list.SetName(fmt::format("Cube Rendering {}", frame.index));
174frame.execute_cmd_list_set = rhi::CommandListSet({ frame.render_cmd_list.GetInterface() }, frame.index);
175}
176
177UserInterfaceApp::CompleteInitialization();
178}
179
180bool TexturedCubeApp::Animate(double, double delta_seconds)
181{
182const float rotation_angle_rad = static_cast<float>(delta_seconds * 360.F / 4.F) * gfx::ConstFloat::RadPerDeg;
183hlslpp::float3x3 light_rotate_matrix = hlslpp::float3x3::rotation_axis(m_camera.GetOrientation().up, rotation_angle_rad);
184m_shader_uniforms.light_position = hlslpp::mul(m_shader_uniforms.light_position, light_rotate_matrix);
185m_camera.Rotate(m_camera.GetOrientation().up, static_cast<float>(delta_seconds * 360.F / 8.F));
186return true;
187}
188
189bool TexturedCubeApp::Resize(const gfx::FrameSize& frame_size, bool is_minimized)
190{
191// Resize screen color and depth textures
192if (!UserInterfaceApp::Resize(frame_size, is_minimized))
193return false;
194
195m_camera.Resize(frame_size);
196return true;
197}
198
199bool TexturedCubeApp::Update()
200{
201if (!UserInterfaceApp::Update())
202return false;
203
204// Update Model, View, Projection matrices based on camera location
205m_shader_uniforms.mvp_matrix = hlslpp::transpose(hlslpp::mul(m_shader_uniforms.model_matrix, m_camera.GetViewProjMatrix()));
206m_shader_uniforms.eye_position = m_camera.GetOrientation().eye;
207
208return true;
209}
210
211bool TexturedCubeApp::Render()
212{
213if (!UserInterfaceApp::Render())
214return false;
215
216// Update uniforms buffer related to current frame
217const TexturedCubeFrame& frame = GetCurrentFrame();
218const rhi::CommandQueue& render_cmd_queue = GetRenderContext().GetRenderCommandKit().GetQueue();
219frame.uniforms_buffer.SetData(render_cmd_queue, m_shader_uniforms_subresource);
220
221// Issue commands for cube rendering
222META_DEBUG_GROUP_VAR(s_debug_group, "Cube Rendering");
223frame.render_cmd_list.ResetWithState(m_render_state, &s_debug_group);
224frame.render_cmd_list.SetViewState(GetViewState());
225frame.render_cmd_list.SetProgramBindings(frame.program_bindings);
226frame.render_cmd_list.SetVertexBuffers(m_vertex_buffer_set);
227frame.render_cmd_list.SetIndexBuffer(m_index_buffer);
228frame.render_cmd_list.DrawIndexed(rhi::RenderPrimitive::Triangle);
229
230RenderOverlay(frame.render_cmd_list);
231
232// Execute command list on render queue and present frame to screen
233frame.render_cmd_list.Commit();
234render_cmd_queue.Execute(frame.execute_cmd_list_set);
235GetRenderContext().Present();
236
237return true;
238}
239
240void TexturedCubeApp::OnContextReleased(rhi::IContext& context)
241{
242m_texture_sampler = {};
243m_cube_texture = {};
244m_const_buffer = {};
245m_index_buffer = {};
246m_vertex_buffer_set = {};
247m_render_state = {};
248
249UserInterfaceApp::OnContextReleased(context);
250}
251
252} // namespace Methane::Tutorials
253
254int main(int argc, const char* argv[])
255{
256return Methane::Tutorials::TexturedCubeApp().Run({ argc, argv });
257}
258