Skip to content

Commit 47e0fab

Browse files
committed
Add example for vsg::LOD nodes
1 parent e48d973 commit 47e0fab

File tree

3 files changed

+310
-0
lines changed

3 files changed

+310
-0
lines changed

examples/nodes/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
add_subdirectory(vsgannotation)
22
add_subdirectory(vsggroups)
3+
add_subdirectory(vsglod)
34
add_subdirectory(vsgtransform)
45
add_subdirectory(vsgtextureprojection)
56
add_subdirectory(vsglayers)

examples/nodes/vsglod/CMakeLists.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
set(SOURCES
2+
vsglod.cpp
3+
)
4+
5+
add_executable(vsglod ${SOURCES})
6+
7+
target_link_libraries(vsglod vsg::vsg)
8+
9+
if (Tracy_FOUND)
10+
target_compile_definitions(vsglod PRIVATE Tracy_FOUND)
11+
target_link_libraries(vsglod Tracy::TracyClient)
12+
endif()
13+
14+
install(TARGETS vsglod RUNTIME DESTINATION bin)

examples/nodes/vsglod/vsglod.cpp

Lines changed: 295 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,295 @@
1+
#include <vsg/all.h>
2+
3+
#ifdef Tracy_FOUND
4+
# include <vsg/utils/TracyInstrumentation.h>
5+
#endif
6+
7+
#include <iostream>
8+
9+
struct ModelSettings
10+
{
11+
vsg::ref_ptr<vsg::Options> options;
12+
double lodMinScreenRatio = 0.01;
13+
};
14+
15+
vsg::ref_ptr<vsg::Node> createTestScene(const ModelSettings& settings)
16+
{
17+
auto builder = vsg::Builder::create();
18+
builder->options = settings.options;
19+
20+
auto scene = vsg::Group::create();
21+
22+
vsg::GeometryInfo geomInfo;
23+
geomInfo.color.set(1.0f, 1.0f, 0.5f, 1.0f);
24+
vsg::StateInfo stateInfo;
25+
26+
auto group = vsg::Group::create();
27+
auto node = builder->createCone(geomInfo, stateInfo);
28+
29+
auto lod = vsg::LOD::create();
30+
auto bb = vsg::visit<vsg::ComputeBounds>(node).bounds;
31+
lod->bound = vsg::dsphere((bb.min + bb.max) * 0.5, vsg::length(bb.max - bb.min));
32+
lod->addChild(vsg::LOD::Child{settings.lodMinScreenRatio+1, node});
33+
group->addChild(lod);
34+
35+
geomInfo.position += geomInfo.dx * 1.5f;
36+
auto node2 = builder->createCylinder(geomInfo, stateInfo);
37+
38+
auto lod2 = vsg::LOD::create();
39+
auto bb2 = vsg::visit<vsg::ComputeBounds>(node2).bounds;
40+
lod2->bound = vsg::dsphere((bb2.min + bb2.max) * 0.5, vsg::length(bb2.max - bb2.min));
41+
lod2->addChild(vsg::LOD::Child{settings.lodMinScreenRatio, node2});
42+
group->addChild(lod2);
43+
44+
scene->addChild(group);
45+
46+
auto bounds = vsg::visit<vsg::ComputeBounds>(scene).bounds;
47+
vsg::info("createTestScene() extents = ", bounds);
48+
49+
return scene;
50+
}
51+
52+
int main(int argc, char** argv)
53+
{
54+
// set up defaults and read command line arguments to override them
55+
auto options = vsg::Options::create();
56+
options->paths = vsg::getEnvPaths("VSG_FILE_PATH");
57+
options->sharedObjects = vsg::SharedObjects::create();
58+
59+
auto windowTraits = vsg::WindowTraits::create();
60+
windowTraits->windowTitle = "vsglod";
61+
62+
// set up defaults and read command line arguments to override them
63+
vsg::CommandLine arguments(&argc, argv);
64+
windowTraits->debugLayer = arguments.read({"--debug", "-d"});
65+
windowTraits->apiDumpLayer = arguments.read({"--api", "-a"});
66+
windowTraits->synchronizationLayer = arguments.read("--sync");
67+
68+
bool reportAverageFrameRate = arguments.read("--fps");
69+
arguments.read("--screen", windowTraits->screenNum);
70+
arguments.read("--display", windowTraits->display);
71+
auto numFrames = arguments.value(-1, "-f");
72+
if (arguments.read({"--fullscreen", "--fs"})) windowTraits->fullscreen = true;
73+
if (arguments.read({"--window", "-w"}, windowTraits->width, windowTraits->height)) { windowTraits->fullscreen = false; }
74+
if (arguments.read("--IMMEDIATE")) windowTraits->swapchainPreferences.presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
75+
if (arguments.read("--d32")) windowTraits->depthFormat = VK_FORMAT_D32_SFLOAT;
76+
arguments.read("--samples", windowTraits->samples);
77+
if (arguments.read({"-t", "--test"}))
78+
{
79+
windowTraits->swapchainPreferences.presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
80+
windowTraits->fullscreen = true;
81+
reportAverageFrameRate = true;
82+
}
83+
if (arguments.read("--st"))
84+
{
85+
windowTraits->swapchainPreferences.presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
86+
windowTraits->width = 192, windowTraits->height = 108;
87+
windowTraits->decoration = false;
88+
reportAverageFrameRate = true;
89+
}
90+
91+
const double invalid_time = std::numeric_limits<double>::max();
92+
auto duration = arguments.value(invalid_time, "--duration");
93+
94+
vsg::ref_ptr<vsg::Instrumentation> instrumentation;
95+
if (arguments.read({"--gpu-annotation", "--ga"}) && vsg::isExtensionSupported(VK_EXT_DEBUG_UTILS_EXTENSION_NAME))
96+
{
97+
windowTraits->debugUtils = true;
98+
99+
auto gpu_instrumentation = vsg::GpuAnnotation::create();
100+
if (arguments.read("--func")) gpu_instrumentation->labelType = vsg::GpuAnnotation::SourceLocation_function;
101+
102+
instrumentation = gpu_instrumentation;
103+
}
104+
else if (arguments.read({"--profiler", "--pr"}))
105+
{
106+
// set Profiler options
107+
auto settings = vsg::Profiler::Settings::create();
108+
arguments.read("--cpu", settings->cpu_instrumentation_level);
109+
arguments.read("--gpu", settings->gpu_instrumentation_level);
110+
arguments.read("--log-size", settings->log_size);
111+
arguments.read("--gpu-size", settings->gpu_timestamp_size);
112+
113+
// create the profiler
114+
instrumentation = vsg::Profiler::create(settings);
115+
}
116+
#ifdef Tracy_FOUND
117+
else if (arguments.read("--tracy"))
118+
{
119+
windowTraits->deviceExtensionNames.push_back(VK_EXT_CALIBRATED_TIMESTAMPS_EXTENSION_NAME);
120+
121+
auto tracy_instrumentation = vsg::TracyInstrumentation::create();
122+
arguments.read("--cpu", tracy_instrumentation->settings->cpu_instrumentation_level);
123+
arguments.read("--gpu", tracy_instrumentation->settings->gpu_instrumentation_level);
124+
instrumentation = tracy_instrumentation;
125+
}
126+
#endif
127+
128+
double nearFarRatio = arguments.value<double>(0.001, "--nf");
129+
ModelSettings settings;
130+
settings.options = options;
131+
132+
vsg::ref_ptr<vsg::ResourceHints> resourceHints;
133+
if (auto resourceHintsFilename = arguments.value<vsg::Path>("", "--rh"))
134+
{
135+
resourceHints = vsg::read_cast<vsg::ResourceHints>(resourceHintsFilename, options);
136+
}
137+
138+
if (!resourceHints) resourceHints = vsg::ResourceHints::create();
139+
140+
if (auto outputResourceHintsFilename = arguments.value<vsg::Path>("", "--orh"))
141+
{
142+
if (!resourceHints) resourceHints = vsg::ResourceHints::create();
143+
vsg::write(resourceHints, outputResourceHintsFilename, options);
144+
return 0;
145+
}
146+
147+
auto shaderHints = vsg::ShaderCompileSettings::create();
148+
vsg::ref_ptr<vsg::ShadowSettings> shadowSettings;
149+
150+
auto pathFilename = arguments.value<vsg::Path>("", "-p");
151+
auto outputFilename = arguments.value<vsg::Path>("", "-o");
152+
153+
auto inherit = arguments.read("--inherit");
154+
auto direction = arguments.value(vsg::dvec3(0.0, 0.0, -1.0), "--direction");
155+
auto angleSubtended = arguments.value<float>(0.0090f, "--angleSubtended");
156+
157+
vsg::ref_ptr<vsg::StateGroup> stateGroup;
158+
if (inherit)
159+
{
160+
auto shaderSet = vsg::createPhongShaderSet(options);
161+
auto layout = shaderSet->createPipelineLayout({}, {0, 1});
162+
163+
stateGroup = vsg::StateGroup::create();
164+
165+
uint32_t vds_set = 0;
166+
stateGroup->add(vsg::BindViewDescriptorSets::create(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, vds_set));
167+
168+
vsg::info("Added state to inherit ");
169+
options->inheritedState = stateGroup->stateCommands;
170+
}
171+
172+
vsg::ref_ptr<vsg::Node> scene;
173+
scene = createTestScene(settings);
174+
175+
if (stateGroup)
176+
{
177+
// if setup place the StateGroup at the root of the scene graph
178+
stateGroup->addChild(scene);
179+
scene = stateGroup;
180+
}
181+
182+
// compute the bounds of the scene graph to help position camera
183+
auto bounds = vsg::visit<vsg::ComputeBounds>(scene).bounds;
184+
auto viewingDistance = vsg::length(bounds.max - bounds.min) * 2.0;
185+
186+
vsg::ref_ptr<vsg::LookAt> lookAt;
187+
188+
{
189+
vsg::dvec3 centre = (bounds.min + bounds.max) * 0.5;
190+
191+
// set up the camera
192+
lookAt = vsg::LookAt::create(centre + vsg::dvec3(0.0, -viewingDistance, 0.0), centre, vsg::dvec3(0.0, 0.0, 1.0));
193+
}
194+
195+
//auto span = vsg::length(bounds.max - bounds.min);
196+
auto group = vsg::Group::create();
197+
group->addChild(scene);
198+
199+
vsg::ref_ptr<vsg::DirectionalLight> directionalLight;
200+
directionalLight = vsg::DirectionalLight::create();
201+
directionalLight->name = "directional";
202+
directionalLight->color.set(1.0f, 1.0f, 1.0f);
203+
directionalLight->intensity = 0.95f;
204+
directionalLight->direction = direction;
205+
directionalLight->angleSubtended = angleSubtended;
206+
directionalLight->shadowSettings = shadowSettings;
207+
208+
group->addChild(directionalLight);
209+
210+
scene = group;
211+
212+
// write out scene if required
213+
if (!outputFilename.empty())
214+
{
215+
vsg::write(scene, outputFilename, options);
216+
return 0;
217+
}
218+
219+
// create the viewer and assign window(s) to it
220+
auto viewer = vsg::Viewer::create();
221+
222+
auto window = vsg::Window::create(windowTraits);
223+
if (!window)
224+
{
225+
std::cout << "Could not create windows." << std::endl;
226+
return 1;
227+
}
228+
229+
viewer->addWindow(window);
230+
231+
vsg::ref_ptr<vsg::ProjectionMatrix> perspective;
232+
perspective = vsg::Perspective::create(30.0, static_cast<double>(window->extent2D().width) / static_cast<double>(window->extent2D().height), nearFarRatio * viewingDistance, viewingDistance * 1.3);
233+
234+
auto camera = vsg::Camera::create(perspective, lookAt, vsg::ViewportState::create(window->extent2D()));
235+
236+
// add the camera and scene graph to View
237+
auto view = vsg::View::create();
238+
view->camera = camera;
239+
view->addChild(scene);
240+
241+
// add close handler to respond the close window button and pressing escape
242+
viewer->addEventHandler(vsg::CloseHandler::create(viewer));
243+
244+
auto cameraAnimation = vsg::CameraAnimationHandler::create(camera, pathFilename, options);
245+
viewer->addEventHandler(cameraAnimation);
246+
if (cameraAnimation->animation)
247+
{
248+
cameraAnimation->play();
249+
if (reportAverageFrameRate && duration == invalid_time) duration = cameraAnimation->animation->maxTime();
250+
}
251+
252+
viewer->addEventHandler(vsg::Trackball::create(camera));
253+
254+
auto renderGraph = vsg::RenderGraph::create(window, view);
255+
auto commandGraph = vsg::CommandGraph::create(window, renderGraph);
256+
viewer->assignRecordAndSubmitTaskAndPresentation({commandGraph});
257+
258+
if (instrumentation) viewer->assignInstrumentation(instrumentation);
259+
260+
viewer->compile(resourceHints);
261+
262+
auto startTime = vsg::clock::now();
263+
double numFramesCompleted = 0.0;
264+
265+
// rendering main loop
266+
while (viewer->advanceToNextFrame() && (numFrames < 0 || (numFrames--) > 0) && (viewer->getFrameStamp()->simulationTime < duration))
267+
{
268+
// pass any events into EventHandlers assigned to the Viewer
269+
viewer->handleEvents();
270+
viewer->update();
271+
272+
viewer->recordAndSubmit();
273+
274+
viewer->present();
275+
276+
numFramesCompleted += 1.0;
277+
}
278+
279+
if (reportAverageFrameRate)
280+
{
281+
auto elapesedTime = std::chrono::duration<double, std::chrono::seconds::period>(vsg::clock::now() - startTime).count();
282+
if (numFramesCompleted > 0.0)
283+
{
284+
std::cout << "Average frame rate = " << (numFramesCompleted / elapesedTime) << std::endl;
285+
}
286+
}
287+
288+
if (auto profiler = instrumentation.cast<vsg::Profiler>())
289+
{
290+
instrumentation->finish();
291+
profiler->log->report(std::cout);
292+
}
293+
294+
return 0;
295+
}

0 commit comments

Comments
 (0)