Skip to content

Commit 52c32a7

Browse files
committed
Add example for vsg::LOD nodes
This example shows various settings for the use of LOD.
1 parent e48d973 commit 52c32a7

File tree

3 files changed

+335
-0
lines changed

3 files changed

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

0 commit comments

Comments
 (0)