Replies: 6 comments 4 replies
-
The ReaderWriter::read(..) method only returns a ref_ptr but that means it's compatible with all types of objects including nodes that can be created by the VSG. What this means that code that calls vsg::read(..) or directly calls a ReaderWriter::read() will need to cast the object returned to the type that want to work with, and to help with this one usually uses the vsg::read_cast(..) template function call rather than vsg::read(), this read_cast<> is equivalent to reading an object then doing a dynamic_cast or it. If you look at most of the VSG examples you'll see vsg::read_castvsg::Node(..) usage when reading a scene graph and then using it for assigning to the viewer for rendering. In you own MyTriangleLoader class it's look OK from a first quick look. You won't be able to render the node directly by just assigning to the viewer as it doesn't have any program state associated with it. If you add it to a scene graph that sets up the state with a StateGroup that is compatible with the your triangle subgraph then it'll work. What you'll find in most of the ReaderWriter implementations is that they create a StateGroup's with the VertexIndexDraw etc. below them. The StageGraph provide all the state like BindGraphicsPipeline etc. for rendering the subgraph. |
Beta Was this translation helpful? Give feedback.
-
I tried copying and simplifying the //======================================================================
// An example of how to do a reader writer that returns a static triangle
//
// Doesn't work. :-(
//
// Dov Grobgeld <[email protected]>
// Sat Mar 16 23:25:06 2024
//----------------------------------------------------------------------
#include <vsg/all.h>
#include <iostream>
#include <vsg/app/ProjectionMatrix.h>
// A triangle loader example that returns static geometry
class MyTriangleLoader : public vsg::Inherit<vsg::ReaderWriter, MyTriangleLoader>
{
public:
MyTriangleLoader() {}
~MyTriangleLoader() {}
vsg::ref_ptr<vsg::Object> read(const vsg::Path& filename = "",
vsg::ref_ptr<const vsg::Options> options = nullptr) const override;
};
// A simplified version of the createStateGroup in Builder.cpp. What am I missing?
vsg::ref_ptr<vsg::StateGroup> createStateGroup()
{
auto options = vsg::Options::create();
vsg::ref_ptr<vsg::ShaderSet> shaderSet = vsg::createFlatShadedShaderSet(options);
auto graphicsPipelineConfig = vsg::GraphicsPipelineConfigurator::create(shaderSet);
// set up graphics pipeline
vsg::DescriptorSetLayoutBindings descriptorBindings;
graphicsPipelineConfig->enableArray("vsg_Vertex", VK_VERTEX_INPUT_RATE_VERTEX, 12);
graphicsPipelineConfig->enableArray("vsg_Normal", VK_VERTEX_INPUT_RATE_VERTEX, 12);
graphicsPipelineConfig->enableArray("vsg_Color", VK_VERTEX_INPUT_RATE_VERTEX, 12);
vsg::StateCommands stateCommands;
graphicsPipelineConfig->init();
auto stateGroup = vsg::StateGroup::create();
stateGroup->stateCommands.swap(stateCommands);
stateGroup->prototypeArrayState = graphicsPipelineConfig->getSuitableArrayState();
return stateGroup;
}
// Create a static triangle
vsg::ref_ptr<vsg::Object> MyTriangleLoader::read(const vsg::Path& filename,
vsg::ref_ptr<const vsg::Options> options) const
{
// Create a triangle
vsg::ref_ptr<vsg::vec3Array> vertices = vsg::vec3Array::create(3);
(*vertices)[0] = vsg::vec3(0.0, 0.0, 0.0);
(*vertices)[1] = vsg::vec3(1.0, 0.0, 0.0);
(*vertices)[2] = vsg::vec3(0.0, 1.0, 0.0);
vsg::ref_ptr<vsg::vec3Array> normals = vsg::vec3Array::create(3);
(*normals)[0] = vsg::vec3(0.0, 0.0, 1.0);
(*normals)[1] = vsg::vec3(0.0, 0.0, 1.0);
(*normals)[2] = vsg::vec3(0.0, 0.0, 1.0);
vsg::ref_ptr<vsg::vec4Array> colors = vsg::vec4Array::create(3);
(*colors)[0] = vsg::vec4(1.0, 0.0, 0.0, 1.0);
(*colors)[1] = vsg::vec4(0.0, 1.0, 0.0, 1.0);
(*colors)[2] = vsg::vec4(0.0, 0.0, 1.0, 1.0);
vsg::ref_ptr<vsg::ushortArray> indices = vsg::ushortArray::create(3);
(*indices)[0] = 0;
(*indices)[1] = 1;
(*indices)[2] = 2;
vsg::ref_ptr<vsg::DrawIndexed> draw = vsg::DrawIndexed::create(3, 1, 0, 0, 0);
vsg::ref_ptr<vsg::Geometry> geometry = vsg::Geometry::create();
vsg::DataList arrays;
arrays.push_back(vertices);
arrays.push_back(normals);
arrays.push_back(colors);
arrays.push_back(indices);
auto vid = vsg::VertexIndexDraw::create();
vid->assignArrays(arrays);
vid->indexCount = static_cast<uint32_t>(indices->size());
vid->assignIndices(indices);
vid->instanceCount = 1;
auto stateGroup = createStateGroup();
stateGroup->addChild(vid);
return stateGroup;
}
int main(int argc, char **argv)
{
auto windowTraits = vsg::WindowTraits::create();
windowTraits->windowTitle = "vsgbuilder";
auto scene = vsg::Group::create();
vsg::StateInfo stateInfo;
#if 1
// Doesn't work. :-(
auto node = MyTriangleLoader().read().cast<vsg::Node>();
scene->addChild(node);
#else
// This works
vsg::GeometryInfo geomInfo;
geomInfo.color = vsg::vec4 {1.0f, 0.0f, 0.0f, 1.0f};
auto builder = vsg::Builder::create();
auto node = builder->createBox(geomInfo, stateInfo);
#endif
scene->addChild(node);
// compute the bounds of the scene graph to help position the camera
vsg::ComputeBounds computeBounds;
scene->accept(computeBounds);
vsg::dvec3 centre = (computeBounds.bounds.min + computeBounds.bounds.max) * 0.5;
// create the viewer and assign window(s) to it
auto viewer = vsg::Viewer::create();
auto window = vsg::Window::create(windowTraits);
if (!window)
{
std::cout << "Could not create window." << std::endl;
return 1;
}
viewer->addWindow(window);
vsg::ref_ptr<vsg::LookAt> lookAt;
// set up the camera
double radius = 1.0;
lookAt = vsg::LookAt::create(centre + vsg::dvec3(-radius*0.5, -radius*0.3, -radius)*3.5, centre, vsg::dvec3(0.0, 0.0, 1.0));
double nearFarRatio = 0.001;
auto perspective = vsg::Perspective::create(30.0, static_cast<double>(window->extent2D().width) / static_cast<double>(window->extent2D().height), nearFarRatio * radius, radius * 10.0);
auto camera = vsg::Camera::create(perspective, lookAt, vsg::ViewportState::create(window->extent2D()));
viewer->addEventHandler(vsg::CloseHandler::create(viewer));
auto trackball = vsg::Trackball::create(camera);
viewer->addEventHandler(trackball);
auto commandGraph = vsg::createCommandGraphForView(window, camera, scene);
viewer->assignRecordAndSubmitTaskAndPresentation({commandGraph});
viewer->compile();
auto startTime = vsg::clock::now();
double numFramesCompleted = 0.0;
// rendering main loop
while (viewer->advanceToNextFrame())
{
viewer->handleEvents();
viewer->update();
viewer->recordAndSubmit();
viewer->present();
numFramesCompleted += 1.0;
}
auto duration = std::chrono::duration<double, std::chrono::seconds::period>(vsg::clock::now() - startTime).count();
if (numFramesCompleted > 0.0)
std::cout << "Average frame rate = " << (numFramesCompleted / duration) << std::endl;
return 0;
exit(0);
}
|
Beta Was this translation helpful? Give feedback.
-
Have a look through the vsgExamples for where the StateGroup is set up, there are lots of examples that range for using ShaderSet like vsg::Builder and vsgXchange::assimp do through to creating the shaders and descriptors sets all manually. I think a mesh building functionality in vsg::Builder would be useful, one would have to be careful though as it's quite open ended task so one would need to just target a subset of how one can build meshes, lines & point clouds. |
Beta Was this translation helpful? Give feedback.
-
I finally got the entire triangle ReaderWriter to work. Here is the complete example as a reference for posterity. My main issue was realizing that I had to get and assign the material binding. Should I create a pull request for vsgExample? //======================================================================
// An example of how to do create a vsg::ReaderWriter that returns a static triangle
//
// This example is released under the MIT license.
//
// Dov Grobgeld <[email protected]>
// Sat Mar 16 23:25:06 2024
//----------------------------------------------------------------------
#include <vsg/all.h>
#include <iostream>
#include <vsg/app/ProjectionMatrix.h>
// A triangle loader example that returns static geometry
class MyTriangleLoader : public vsg::Inherit<vsg::ReaderWriter, MyTriangleLoader>
{
public:
MyTriangleLoader() {}
vsg::ref_ptr<vsg::Object> read(const vsg::Path& /*filename*/ = "",
vsg::ref_ptr<const vsg::Options> options = nullptr) const override;
};
// A simplified version of the createStateGroup in Builder.cpp.
vsg::ref_ptr<vsg::StateGroup> createStateGroup()
{
auto options = nullptr;
vsg::ref_ptr<vsg::ShaderSet> shaderSet = vsg::createFlatShadedShaderSet(options);
auto graphicsPipelineConfig = vsg::GraphicsPipelineConfigurator::create(shaderSet);
if (auto& materialBinding = shaderSet->getDescriptorBinding("material"))
{
vsg::ref_ptr<vsg::Data> mat = materialBinding.data;
if (!mat) mat = vsg::PhongMaterialValue::create();
graphicsPipelineConfig->assignDescriptor("material", mat);
}
graphicsPipelineConfig->enableArray("vsg_Vertex", VK_VERTEX_INPUT_RATE_VERTEX, 12);
graphicsPipelineConfig->enableArray("vsg_Normal", VK_VERTEX_INPUT_RATE_VERTEX, 12);
graphicsPipelineConfig->enableArray("vsg_TexCoord0", VK_VERTEX_INPUT_RATE_VERTEX, 8);
graphicsPipelineConfig->enableArray("vsg_Color", VK_VERTEX_INPUT_RATE_VERTEX, 4);
vsg::StateCommands stateCommands;
graphicsPipelineConfig->init();
graphicsPipelineConfig->copyTo(stateCommands);
auto stateGroup = vsg::StateGroup::create();
stateGroup->stateCommands.swap(stateCommands);
stateGroup->prototypeArrayState = graphicsPipelineConfig->getSuitableArrayState();
return stateGroup;
}
// Create a static triangle node
vsg::ref_ptr<vsg::Object> MyTriangleLoader::read(const vsg::Path& /*filename*/,
vsg::ref_ptr<const vsg::Options> /*options*/) const
{
// Set up vertex attributes for a triangle
auto vertices = vsg::vec3Array::create(
{{0.0f, 0.0f, 0.0f},
{0.0f, 1.0f, 0.0f},
{1.0f, 0.0f, 0.0f}});
auto normals = vsg::vec3Array::create(
{{0.0f, 0.0f, 1.0f},
{0.0f, 0.0f, 1.0f},
{0.0f, 0.0f, 1.0f}});
auto texcoords = vsg::vec2Array::create(
{{0.0f, 0.0f},
{0.0f, 1.0f},
{1.0f, 0.0f}});
auto colors = vsg::vec4Array::create(
{{1.0, 0.0, 0.0, 1.0},
{0.0, 1.0, 0.0, 1.0},
{0.0, 0.0, 1.0, 1.0}});
auto indices = vsg::ushortArray::create({0, 1, 2});
vsg::DataList arrays {
vertices,
normals,
texcoords,
colors
};
auto vid = vsg::VertexIndexDraw::create();
vid->assignArrays(arrays);
vid->assignIndices(indices);
vid->indexCount = static_cast<uint32_t>(indices->size());
vid->instanceCount = 1;
auto stateGroup = createStateGroup();
stateGroup->addChild(vid);
return stateGroup;
}
int main(int /*argc*/, char ** /*argv*/)
{
auto windowTraits = vsg::WindowTraits::create();
windowTraits->windowTitle = "A simple readwriter";
windowTraits->debugLayer = true;
auto scene = vsg::Group::create();
// "Load" our triangle
auto node = MyTriangleLoader().read().cast<vsg::Node>();
scene->addChild(node);
// compute the bounds of the scene graph to help position the camera
vsg::ComputeBounds computeBounds;
scene->accept(computeBounds);
vsg::dvec3 centre = (computeBounds.bounds.min + computeBounds.bounds.max) * 0.5;
// create the viewer and assign window(s) to it
auto viewer = vsg::Viewer::create();
auto window = vsg::Window::create(windowTraits);
if (!window)
{
std::cout << "Could not create window." << std::endl;
return 1;
}
viewer->addWindow(window);
// set up the camera
double radius = 1.0;
auto lookAt = vsg::LookAt::create(centre + vsg::dvec3(-radius*0.5, -radius*0.3, -radius)*3.5, centre, vsg::dvec3(0.0, 0.0, 1.0));
double nearFarRatio = 0.001;
auto perspective = vsg::Perspective::create(30.0, static_cast<double>(window->extent2D().width) / static_cast<double>(window->extent2D().height), nearFarRatio * radius, radius * 10.0);
auto camera = vsg::Camera::create(perspective, lookAt, vsg::ViewportState::create(window->extent2D()));
viewer->addEventHandler(vsg::CloseHandler::create(viewer));
viewer->addEventHandler(vsg::Trackball::create(camera));
auto commandGraph = vsg::createCommandGraphForView(window, camera, scene);
viewer->assignRecordAndSubmitTaskAndPresentation({commandGraph});
viewer->compile();
// rendering main loop
while (viewer->advanceToNextFrame())
{
viewer->handleEvents();
viewer->update();
viewer->recordAndSubmit();
viewer->present();
}
exit(0);
} |
Beta Was this translation helpful? Give feedback.
-
As I like bare bone examples, I simplified my previous example further. The below example embeds simplified versions of the shaders, that removed the ifdef sections, as well as the texture uv coordinate. For me it provides a good starting point for expanding to a real loader. Perhaps I'll use this as a basis for writing stand alone STL loader. //======================================================================
// An example of how to do a reader writer that returns a static triangle
//
// This example is released under the MIT license.
//
// Dov Grobgeld <[email protected]>
// Sat Mar 16 23:25:06 2024
//----------------------------------------------------------------------
#include <vsg/all.h>
#include <iostream>
#include <vsg/app/ProjectionMatrix.h>
const auto vert = R"(
#version 450
#extension GL_ARB_separate_shader_objects : enable
#define VIEW_DESCRIPTOR_SET 0
#define MATERIAL_DESCRIPTOR_SET 1
layout(push_constant) uniform PushConstants {
mat4 projection;
mat4 modelView;
} pc;
layout(location = 0) in vec3 vsg_Vertex;
layout(location = 1) in vec3 vsg_Normal;
layout(location = 2) in vec4 vsg_Color;
layout(location = 0) out vec4 vertexColor;
out gl_PerVertex{ vec4 gl_Position; };
void main()
{
vec4 vertex = vec4(vsg_Vertex, 1.0);
vec4 normal = vec4(vsg_Normal, 0.0);
mat4 mv = pc.modelView;
gl_Position = (pc.projection * mv) * vertex;
vertexColor = vsg_Color;
}
)";
const auto frag = R"(
#version 450
#extension GL_ARB_separate_shader_objects : enable
#define VIEW_DESCRIPTOR_SET 0
#define MATERIAL_DESCRIPTOR_SET 1
layout(set = MATERIAL_DESCRIPTOR_SET, binding = 10) uniform MaterialData
{
vec4 ambientColor;
vec4 diffuseColor;
vec4 specularColor;
vec4 emissiveColor;
float shininess;
float alphaMask;
float alphaMaskCutoff;
} material;
layout(location = 0) in vec4 vertexColor;
layout(location = 0) out vec4 outColor;
void main()
{
vec4 diffuseColor = vertexColor * material.diffuseColor;
outColor = diffuseColor;
}
)";
vsg::ref_ptr<vsg::ShaderSet> createShaderSet(vsg::ref_ptr<const vsg::Options> options)
{
auto vertexShader = vsg::ShaderStage::create(VK_SHADER_STAGE_VERTEX_BIT, "main", vert);
auto fragmentShader = vsg::ShaderStage::create(VK_SHADER_STAGE_FRAGMENT_BIT, "main", frag);
#define VIEW_DESCRIPTOR_SET 0
#define MATERIAL_DESCRIPTOR_SET 1
auto shaderSet = vsg::ShaderSet::create(vsg::ShaderStages{vertexShader, fragmentShader});
shaderSet->addAttributeBinding("vsg_Vertex", "", 0, VK_FORMAT_R32G32B32_SFLOAT, vsg::vec3Array::create(1));
shaderSet->addAttributeBinding("vsg_Normal", "", 1, VK_FORMAT_R32G32B32_SFLOAT, vsg::vec3Array::create(1));
shaderSet->addAttributeBinding("vsg_Color", "", 2, VK_FORMAT_R32G32B32A32_SFLOAT, vsg::vec4Array::create(1));
shaderSet->addDescriptorBinding("material", "", MATERIAL_DESCRIPTOR_SET, 10, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, vsg::PhongMaterialValue::create());
shaderSet->addDescriptorBinding("viewportData", "", VIEW_DESCRIPTOR_SET, 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, vsg::vec4Value::create(0, 0, 1280, 1024));
shaderSet->addPushConstantRange("pc", "", VK_SHADER_STAGE_VERTEX_BIT, 0, 128);
shaderSet->customDescriptorSetBindings.push_back(vsg::ViewDependentStateBinding::create(VIEW_DESCRIPTOR_SET));
return shaderSet;
}
// A triangle loader example that returns static geometry
class MyTriangleLoader : public vsg::Inherit<vsg::ReaderWriter, MyTriangleLoader>
{
public:
MyTriangleLoader() {}
vsg::ref_ptr<vsg::Object> read(const vsg::Path& /*filename*/ = "",
vsg::ref_ptr<const vsg::Options> options = nullptr) const override;
};
// A simplified version of the createStateGroup in Builder.cpp.
vsg::ref_ptr<vsg::StateGroup> createStateGroup()
{
auto options = nullptr;
vsg::ref_ptr<vsg::ShaderSet> shaderSet = createShaderSet(options);
auto graphicsPipelineConfig = vsg::GraphicsPipelineConfigurator::create(shaderSet);
if (auto& materialBinding = shaderSet->getDescriptorBinding("material"))
{
vsg::ref_ptr<vsg::Data> mat = materialBinding.data;
if (!mat) mat = vsg::PhongMaterialValue::create();
graphicsPipelineConfig->assignDescriptor("material", mat);
}
graphicsPipelineConfig->enableArray("vsg_Vertex", VK_VERTEX_INPUT_RATE_VERTEX, 12);
graphicsPipelineConfig->enableArray("vsg_Normal", VK_VERTEX_INPUT_RATE_VERTEX, 12);
graphicsPipelineConfig->enableArray("vsg_Color", VK_VERTEX_INPUT_RATE_VERTEX, 4);
vsg::StateCommands stateCommands;
graphicsPipelineConfig->init();
graphicsPipelineConfig->copyTo(stateCommands);
auto stateGroup = vsg::StateGroup::create();
stateGroup->stateCommands.swap(stateCommands);
stateGroup->prototypeArrayState = graphicsPipelineConfig->getSuitableArrayState();
return stateGroup;
}
// Create a static triangle node
vsg::ref_ptr<vsg::Object> MyTriangleLoader::read(const vsg::Path& /*filename*/,
vsg::ref_ptr<const vsg::Options> /*options*/) const
{
// Set up vertex attributes for a triangle
auto vertices = vsg::vec3Array::create(
{{0.0f, 0.0f, 0.0f},
{0.0f, 1.0f, 0.0f},
{1.0f, 0.0f, 0.0f}});
auto normals = vsg::vec3Array::create(
{{0.0f, 0.0f, 1.0f},
{0.0f, 0.0f, 1.0f},
{0.0f, 0.0f, 1.0f}});
auto colors = vsg::vec4Array::create(
{{1.0, 0.0, 0.0, 1.0},
{0.0, 1.0, 0.0, 1.0},
{0.0, 0.0, 1.0, 1.0}});
auto indices = vsg::ushortArray::create({0, 1, 2});
vsg::DataList arrays {
vertices,
normals,
colors
};
auto vid = vsg::VertexIndexDraw::create();
vid->assignArrays(arrays);
vid->assignIndices(indices);
vid->indexCount = static_cast<uint32_t>(indices->size());
vid->instanceCount = 1;
auto stateGroup = createStateGroup();
stateGroup->addChild(vid);
return stateGroup;
}
int main(int /*argc*/, char ** /*argv*/)
{
auto windowTraits = vsg::WindowTraits::create();
windowTraits->windowTitle = "A simple readwriter";
windowTraits->debugLayer = true;
auto scene = vsg::Group::create();
// "Load" our triangle
auto node = MyTriangleLoader().read().cast<vsg::Node>();
scene->addChild(node);
// compute the bounds of the scene graph to help position the camera
vsg::ComputeBounds computeBounds;
scene->accept(computeBounds);
vsg::dvec3 centre = (computeBounds.bounds.min + computeBounds.bounds.max) * 0.5;
// create the viewer and assign window(s) to it
auto viewer = vsg::Viewer::create();
auto window = vsg::Window::create(windowTraits);
if (!window)
{
std::cout << "Could not create window." << std::endl;
return 1;
}
viewer->addWindow(window);
// set up the camera
double radius = 1.0;
auto lookAt = vsg::LookAt::create(centre + vsg::dvec3(-radius*0.5, -radius*0.3, -radius)*3.5, centre, vsg::dvec3(0.0, 0.0, 1.0));
double nearFarRatio = 0.001;
auto perspective = vsg::Perspective::create(30.0, static_cast<double>(window->extent2D().width) / static_cast<double>(window->extent2D().height), nearFarRatio * radius, radius * 10.0);
auto camera = vsg::Camera::create(perspective, lookAt, vsg::ViewportState::create(window->extent2D()));
viewer->addEventHandler(vsg::CloseHandler::create(viewer));
viewer->addEventHandler(vsg::Trackball::create(camera));
auto commandGraph = vsg::createCommandGraphForView(window, camera, scene);
viewer->assignRecordAndSubmitTaskAndPresentation({commandGraph});
viewer->compile();
// rendering main loop
while (viewer->advanceToNextFrame())
{
viewer->handleEvents();
viewer->update();
viewer->recordAndSubmit();
viewer->present();
}
exit(0);
} |
Beta Was this translation helpful? Give feedback.
-
Here is my stl reader for posterity, using what I learned above. I introduced a geometry shader to minimize the GPU footprint. //======================================================================
// hello-stl-reader.cpp
//
// A stand alone stl reader vsg::ReaderWriter implementation. The
// reader is using a geometry shader to calculate normals for
// minimal GPU memory footprint.
//
// This example is released under the MIT license.
//
// Dov Grobgeld <[email protected]>
// Sat Mar 16 23:25:06 2024
//----------------------------------------------------------------------
#include <vsg/all.h>
#include <iostream>
#include <vsg/app/ProjectionMatrix.h>
#include <fmt/core.h>
using namespace std;
using fmt::print;
class VsgMeshException : public std::runtime_error {
public:
VsgMeshException(const std::string& msg) : std::runtime_error(msg) {}
};
// A stl like mesh
class VsgMesh {
public:
VsgMesh(const std::string& fileName) {
load_stl(fileName);
}
void load_stl(const std::string& fileName);
// Each three vertices make up a triangle
std::vector<vsg::vec3> vertices;
};
// Load an stl file into the mesh
void VsgMesh::load_stl(const string& Filename)
{
ifstream inf(Filename, ios::binary);
if (!inf.good())
throw VsgMeshException("Could not open file: " + Filename);
char Title[80];
int FacesNum;
//Ignore 80 char title
inf.read(Title, 80);
if (strncmp(Title,"facet",5)==0) //ASCII format
throw VsgMeshException("ASCII STL files not supported!");
//Read number of faces
inf.read((char*)&FacesNum, 4);
float VertexData[12]; // normal=3, vertices=3*3 = 12
short Spacer; // Sometimes used for color, we ignore it
vertices.clear();
vertices.reserve(FacesNum*3);
// Bin stl: Normal(3*float), vertices(9*float), 2 Bytes Spacer
for (int i=0; i<(int)FacesNum; i++)
{
inf.read((char*)&VertexData[0], sizeof(float) * 12);
inf.read((char*)&Spacer, 2); // spacer
// Skip normal. It will be recalculated in the geometry shader
for (int j = 3; j < 12; j+=3)
vertices.emplace_back(VertexData[j], VertexData[j+1], VertexData[j+2]);
}
}
const auto vert = R"(
#version 450
#extension GL_ARB_separate_shader_objects : enable
#define MATERIAL_DESCRIPTOR_SET 1
layout(push_constant) uniform PushConstants {
mat4 projection;
mat4 modelView;
} pc;
layout(set = MATERIAL_DESCRIPTOR_SET, binding = 10) uniform MaterialData
{
vec4 ambientColor;
vec4 diffuseColor;
vec4 specularColor;
vec4 emissiveColor;
float shininess;
float alphaMask;
float alphaMaskCutoff;
} material;
layout(location = 0) in vec3 vsg_Vertex;
layout(location = 0) out vec4 vertexColor;
layout(location = 1) out vec3 geom_in_vertex;
void main()
{
vec4 vertex = vec4(vsg_Vertex, 1.0);
mat4 mv = pc.modelView;
gl_Position = (pc.projection * mv) * vertex;
vertexColor = material.ambientColor;
geom_in_vertex = (mv * vertex).xyz;
}
)";
// A geometry shader that calculates normals and baryocentric coordinates
// and passes them to the fragment shader
const auto geom = R"(
#version 450
layout(triangles) in;
layout(triangle_strip, max_vertices=3) out;
// Input from the vertex shader
layout(location = 0) in vec4 vertexColor[];
layout(location = 1) in vec3 geom_in_vertex[];
// Outputs
layout(location = 0) out vec4 outVertexColor;
layout(location = 1) out vec3 normal;
layout(location = 2) out vec3 vBC;
layout(location = 3) out vec3 pos;
void main()
{
vec3 v1 = geom_in_vertex[1] - geom_in_vertex[0];
vec3 v2 = geom_in_vertex[2] - geom_in_vertex[0];
vec3 vnorm = cross(normalize(v1),normalize(v2));
for (int i=0; i<3; i++) {
gl_Position = gl_in[i].gl_Position; // pass through eye coordinate
normal = vnorm; // amend the normals
vBC = vec3(int(i==0),
int(i==1),
int(i==2));
outVertexColor = vertexColor[i];
pos = geom_in_vertex[i];
EmitVertex();
}
EndPrimitive();
}
)";
// A fragment shader for phong shading with two hardcoded lights
const auto frag = R"(
#version 450
#extension GL_ARB_separate_shader_objects : enable
#define MATERIAL_DESCRIPTOR_SET 1
layout(set = MATERIAL_DESCRIPTOR_SET, binding = 10) uniform MaterialData
{
vec4 ambientColor;
vec4 diffuseColor;
vec4 specularColor;
vec4 emissiveColor;
float shininess;
float alphaMask;
float alphaMaskCutoff;
} material;
layout(location = 0) in vec4 vertexColor;
layout(location = 1) in vec3 normal;
layout(location = 2) in vec3 vBC;
layout(location = 3) in vec3 pos;
layout(location = 0) out vec4 outColor;
// TBD - make these uniforms
const float lightStrength1 = 0.25;
const vec3 lightPos1 = vec3(-1e4,0.5e4,1e4);
const vec3 lightPos = vec3(0,0,5);
void main() {
// First light
vec3 N = normalize(normal);
vec3 L = normalize(lightPos - pos);
vec3 R = reflect(-L, N); // Reflected light vector
vec3 V = -normalize(pos); // Vector to viewer
float Kd = max(dot(L,N), 0.0);
float Ks = pow(max(dot(R,V),0.0), material.shininess)*0.6;
// Second light
L = normalize(lightPos1 - pos);
R = reflect(-L, N);
Kd += max(dot(L,N), 0.0) * lightStrength1;
Ks += pow(max(dot(R,V),0.0), material.shininess) * lightStrength1;
outColor = vec4(
vec3(material.ambientColor.xyz
+ material.diffuseColor.xyz * Kd
+ material.specularColor.xyz * Ks)*0.5,
1.0 // Non transparent
);
}
)";
vsg::ref_ptr<vsg::ShaderSet> createShaderSet(vsg::ref_ptr<const vsg::Options> /*options*/)
{
auto vertexShader = vsg::ShaderStage::create(VK_SHADER_STAGE_VERTEX_BIT, "main", vert);
auto geomShader = vsg::ShaderStage::create(VK_SHADER_STAGE_GEOMETRY_BIT, "main", geom);
auto fragmentShader = vsg::ShaderStage::create(VK_SHADER_STAGE_FRAGMENT_BIT, "main", frag);
#define VIEW_DESCRIPTOR_SET 0
#define MATERIAL_DESCRIPTOR_SET 1
auto shaderSet = vsg::ShaderSet::create(vsg::ShaderStages{vertexShader, geomShader, fragmentShader});
shaderSet->addAttributeBinding("vsg_Vertex", "", 0, VK_FORMAT_R32G32B32_SFLOAT, vsg::vec3Array::create(1));
auto material = vsg::PhongMaterialValue::create();
material->value().ambient = vsg::vec4 { 0.1, 0.1, 0.1, 1.0 };
material->value().diffuse = vsg::vec4 { 1.0, 1.0, 1.0, 1.0 };
material->value().specular = vsg::vec4 { 1.0, 1.0, 1.0, 1.0 };
material->value().shininess = 10;
shaderSet->addDescriptorBinding("material", "", MATERIAL_DESCRIPTOR_SET, 10, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, material);
shaderSet->addDescriptorBinding("viewportData", "", VIEW_DESCRIPTOR_SET, 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, vsg::vec4Value::create(0, 0, 1280, 1024));
shaderSet->addPushConstantRange("pc", "", VK_SHADER_STAGE_VERTEX_BIT, 0, 128);
shaderSet->customDescriptorSetBindings.push_back(vsg::ViewDependentStateBinding::create(VIEW_DESCRIPTOR_SET));
return shaderSet;
}
// A triangle loader example that returns static geometry
class MyStlLoader : public vsg::Inherit<vsg::ReaderWriter, MyStlLoader>
{
public:
MyStlLoader() {}
vsg::ref_ptr<vsg::Object> read(const vsg::Path& filename,
vsg::ref_ptr<const vsg::Options> options = nullptr) const override;
};
// A simplified version of the createStateGroup in Builder.cpp.
vsg::ref_ptr<vsg::StateGroup> createStateGroup()
{
auto options = nullptr;
vsg::ref_ptr<vsg::ShaderSet> shaderSet = createShaderSet(options);
auto graphicsPipelineConfig = vsg::GraphicsPipelineConfigurator::create(shaderSet);
if (auto& materialBinding = shaderSet->getDescriptorBinding("material"))
{
vsg::ref_ptr<vsg::Data> mat = materialBinding.data;
if (!mat) mat = vsg::PhongMaterialValue::create();
graphicsPipelineConfig->assignDescriptor("material", mat);
}
graphicsPipelineConfig->enableArray("vsg_Vertex", VK_VERTEX_INPUT_RATE_VERTEX, 12);
vsg::StateCommands stateCommands;
graphicsPipelineConfig->init();
graphicsPipelineConfig->copyTo(stateCommands);
auto stateGroup = vsg::StateGroup::create();
stateGroup->stateCommands.swap(stateCommands);
stateGroup->prototypeArrayState = graphicsPipelineConfig->getSuitableArrayState();
return stateGroup;
}
// Create a static triangle node
vsg::ref_ptr<vsg::Object> MyStlLoader::read(const vsg::Path& filename,
vsg::ref_ptr<const vsg::Options> /*options*/) const
{
VsgMesh mesh(filename);
// Set up vertex attributes for a triangle
auto vertices = vsg::vec3Array::create(mesh.vertices.size());
for (size_t i = 0; i < mesh.vertices.size(); ++i)
vertices->set(i, mesh.vertices[i]);
vsg::DataList arrays {
vertices,
};
auto vid = vsg::VertexDraw::create();
vid->assignArrays(arrays);
vid->instanceCount = 1;
vid->vertexCount = vertices->size();
print("Number of vertices: {}\n", vertices->size());
auto stateGroup = createStateGroup();
stateGroup->addChild(vid);
return stateGroup;
}
template <typename... Args>
static void die(fmt::format_string<Args...> FormatStr, Args &&... args)
{
string msg = fmt::format(FormatStr, std::forward<Args>(args)...);
if (msg[msg.size()-1] != '\n')
msg += "\n";
fmt::print(stderr, "{}", msg);
exit(-1);
}
int main(int argc, char **argv)
{
if (argc != 2)
die("Usage: hello-stl-reader <filename.stl>");
std::string filename = argv[1];
auto windowTraits = vsg::WindowTraits::create();
windowTraits->windowTitle = filename;
windowTraits->debugLayer = true;
auto deviceFeatures = windowTraits->deviceFeatures = vsg::DeviceFeatures::create();
deviceFeatures->get().geometryShader = VK_TRUE;
auto scene = vsg::Group::create();
// "Load" our triangle
auto node = MyStlLoader().read(filename).cast<vsg::Node>();
scene->addChild(node);
// compute the bounds of the scene graph to help position the camera
vsg::ComputeBounds computeBounds;
scene->accept(computeBounds);
vsg::dvec3 centre = (computeBounds.bounds.min + computeBounds.bounds.max) * 0.5;
// create the viewer and assign window(s) to it
auto viewer = vsg::Viewer::create();
auto window = vsg::Window::create(windowTraits);
if (!window)
{
std::cout << "Could not create window." << std::endl;
return 1;
}
viewer->addWindow(window);
// set up the camera
auto bounds = computeBounds.bounds;
double radius = max(bounds.max.x - bounds.min.x,
max(bounds.max.y - bounds.min.y,
bounds.max.z - bounds.min.z));
auto lookAt = vsg::LookAt::create(centre + vsg::dvec3(radius, -radius*1.5, 2*radius), centre, vsg::dvec3(0.0, 0.0, 1.0));
double nearFarRatio = 0.001;
auto perspective = vsg::Perspective::create(30.0, static_cast<double>(window->extent2D().width) / static_cast<double>(window->extent2D().height), nearFarRatio * radius, radius * 10.0);
auto camera = vsg::Camera::create(perspective, lookAt, vsg::ViewportState::create(window->extent2D()));
viewer->addEventHandler(vsg::CloseHandler::create(viewer));
viewer->addEventHandler(vsg::Trackball::create(camera));
auto commandGraph = vsg::createCommandGraphForView(window, camera, scene);
viewer->assignRecordAndSubmitTaskAndPresentation({commandGraph});
viewer->compile();
// rendering main loop
while (viewer->advanceToNextFrame())
{
viewer->handleEvents();
viewer->update();
viewer->recordAndSubmit();
viewer->present();
}
exit(0);
} |
Beta Was this translation helpful? Give feedback.
-
I'd like to write a new ReaderWriter for a 3D file format and I am confused of what is needed. As an example I'd like to write a reader that returns a static triangle. I have gotten as far as writing the following implementation for my triangle reader:
This compiles fine. But I'm confused how to use it. I realized that I can't do
addNode()
of the resulting object directly to a scenegraph as it returns avsg::Object
, and not avsg::Node
. So how do I create the node? Note that I currently treat light sources and material as I don't care.Beta Was this translation helpful? Give feedback.
All reactions