#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();
}