#include <osg/Geometry>
#include <osg/Geode>
#include <osg/Program>
#include <osg/VertexAttribDivisor>
#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>
#include <random>
// 創建單個立方體幾何體(共享基礎形狀)
osg::ref_ptr<osg::Geometry> createCubeGeometry(int vtx) {
? ? osg::ref_ptr<osg::Geometry> geom = new osg::Geometry;
? ? // 立方體8個頂點(單位立方體,中心在原點)
? ? osg::Vec3Array* vertices = new osg::Vec3Array;
? ? vertices->push_back(osg::Vec3(-0.5, -0.5, -0.5)); // 0 左前下
? ? vertices->push_back(osg::Vec3(0.5, -0.5, -0.5)); // 1 右前下
? ? vertices->push_back(osg::Vec3(0.5, 0.5, -0.5)); // 2 右后下
? ? vertices->push_back(osg::Vec3(-0.5, 0.5, -0.5)); // 3 左后下
? ? vertices->push_back(osg::Vec3(-0.5, -0.5, 0.5)); // 4 左前上
? ? vertices->push_back(osg::Vec3(0.5, -0.5, 0.5)); // 5 右前上
? ? vertices->push_back(osg::Vec3(0.5, 0.5, 0.5)); // 6 右后上
? ? vertices->push_back(osg::Vec3(-0.5, 0.5, 0.5)); // 7 左后上
? ? geom->setVertexArray(vertices);
? ? // 立方體6個面的法線(用于光照計算)
? ? osg::Vec3Array* normals = new osg::Vec3Array;
? ? normals->push_back(osg::Vec3(0, 0, -1)); // 前面
? ? normals->push_back(osg::Vec3(0, 0, 1)); // 后面
? ? normals->push_back(osg::Vec3(-1, 0, 0)); // 左面
? ? normals->push_back(osg::Vec3(1, 0, 0)); // 右面
? ? normals->push_back(osg::Vec3(0, -1, 0)); // 底面
? ? normals->push_back(osg::Vec3(0, 1, 0)); // 頂面
? ? geom->setNormalArray(normals, osg::Array::BIND_PER_PRIMITIVE_SET);
? ? std::vector<GLuint> idxbuffer;
? ? // 前面
? ? idxbuffer.push_back(0); idxbuffer.push_back(1); idxbuffer.push_back(2);
? ? idxbuffer.push_back(2); idxbuffer.push_back(3); idxbuffer.push_back(0);
? ? // 后面
? ? idxbuffer.push_back(4); idxbuffer.push_back(7); idxbuffer.push_back(6);
? ? idxbuffer.push_back(6); idxbuffer.push_back(5); idxbuffer.push_back(4);
? ? // 左面
? ? idxbuffer.push_back(0); idxbuffer.push_back(3); idxbuffer.push_back(7);
? ? idxbuffer.push_back(7); idxbuffer.push_back(4); idxbuffer.push_back(0);
? ? // 右面
? ? idxbuffer.push_back(1); idxbuffer.push_back(5); idxbuffer.push_back(6);
? ? idxbuffer.push_back(6); idxbuffer.push_back(2); idxbuffer.push_back(1);
? ? // 底面
? ? idxbuffer.push_back(0); idxbuffer.push_back(4); idxbuffer.push_back(5);
? ? idxbuffer.push_back(5); idxbuffer.push_back(1); idxbuffer.push_back(0);
? ? // 頂面
? ? idxbuffer.push_back(3); idxbuffer.push_back(2); idxbuffer.push_back(6);
? ? idxbuffer.push_back(6); idxbuffer.push_back(7); idxbuffer.push_back(3);
? ? // 定義12個三角形(每個面2個三角形)
? ? osg::DrawElementsUInt* indices = new osg::DrawElementsUInt(GL_TRIANGLES, 36, idxbuffer.data(), vtx);
? ? geom->addPrimitiveSet(indices);
? ? geom->setUseDisplayList(false);
? ? geom->setUseVertexBufferObjects(true);
? ? return geom;
}
// 創建實例化變換矩陣數組
osg::ref_ptr<osg::Vec3Array> createInstancePositions(int count) {
? ? osg::ref_ptr<osg::Vec3Array> positions = new osg::Vec3Array;
? ? std::random_device rd;
? ? std::mt19937 gen(rd());
? ? const auto len = sqrt(count);
? ? std::uniform_real_distribution<float> dis(-len, len);
? ? for (int i = 0; i < count; ++i) {
? ? ? ? positions->push_back(osg::Vec3(dis(gen), dis(gen), dis(gen)));
? ? }
? ? return positions;
}
///gl_InstanceID
const std::string ?vertex_shader = R"(
? ? ? ? ? ? ? ? ? ? #version 430 compatibility
? ? ? ? ? ? ? ? ? ? layout(location = 0) in vec3 vertexPosition;
? ? ? ? ? ? ? ? ? ? layout(location = 6) in vec3 instancePosition;
? ? ? ? ? ? ? ? ? ? uniform mat4 osg_ModelViewProjectionMatrix;
? ? ? ? ? ? ? ? ? ? void main() {
? ? ? ? ? ? ? ? ? ? ? ? vec4 pos = vec4(vertexPosition + instancePosition, 1.0);
? ? ? ? ? ? ? ? ? ? ? ? gl_Position = ?gl_ModelViewProjectionMatrix * pos;
? ? ? ? ? ? ? ? ? ? }
)";
const std::string ?frag_shader = R"(
? ? ? ? ? ? ? ? ? ? #version 430 core
? ? ? ? ? ? ? ? ? ? out vec4 fragColor;
? ? ? ? ? ? ? ? ? ? void main() {
? ? ? ? ? ? ? ? ? ? ? ? fragColor = vec4(0.8, 0.3, 0.2, 1.0);?
? ? ? ? ? ? ? ? ? ? }
)";
int main() {
? ? // 創建場景根節點
? ? osg::ref_ptr<osg::Group> root = new osg::Group;
?? ?constexpr int instanceCount = 100; // 實例數量
? ? // 創建共享幾何體
? ? osg::ref_ptr<osg::Geometry> cube = createCubeGeometry(instanceCount);
? ? // 設置實例化屬性(位置)
? ? osg::ref_ptr<osg::Vec3Array> instancePositions = createInstancePositions(instanceCount);
? ? instancePositions->setBinding(osg::Array::Binding::BIND_PER_VERTEX);
? ? cube->setVertexAttribArray(6, instancePositions); // 綁定到屬性索引6
? ? cube->getOrCreateStateSet()->setAttribute(new osg::VertexAttribDivisor(6, 1));//(頂點屬性索引,*實例使用相同的頂點屬)
? ? // 創建幾何節點并添加到場景
? ? osg::ref_ptr<osg::Geode> geode = new osg::Geode;
? ? geode->addDrawable(cube);
? ? root->addChild(geode);
? ? // 配置實例化著色器
? ? osg::ref_ptr<osg::Program> program = new osg::Program;
? ? program->addShader(new osg::Shader(osg::Shader::VERTEX, vertex_shader.c_str()));
? ? program->addShader(new osg::Shader(osg::Shader::FRAGMENT, frag_shader.c_str()));
? ? geode->getOrCreateStateSet()->setAttribute(program);
? ??
? ? // 啟動查看器
? ? osgViewer::Viewer viewer;
? ? viewer.setUpViewInWindow(100, 100, 800, 600);
? ? viewer.setSceneData(root);
? ? viewer.addEventHandler(new osgViewer::StatsHandler());
? ? viewer.getCamera()->setNearFarRatio(1e-5);
? ? viewer.getCamera()->setProjectionMatrixAsPerspective(60, 800 / (float)600, 1, 100);
? ? viewer.getCamera()->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
? ? return viewer.run();
}
?