Last active
December 23, 2021 06:01
-
-
Save vicrucann/497fd5839bccba45e58b5ca48feca12f to your computer and use it in GitHub Desktop.
OpenSceneGraph simple geometry shader example: turns line adjacency into triangle strip (based on cinder line shader)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <Windows.h> | |
#include <osg/Camera> | |
#include <osg/Drawable> | |
#include <osg/Geode> | |
#include <osg/Geometry> | |
#include <osg/Group> | |
#include <osg/Node> | |
#include <osg/NodeVisitor> | |
#include <osg/Object> | |
#include <osg/PrimitiveSet> | |
#include <osg/Program> | |
#include <osg/Shader> | |
#include <osg/StateSet> | |
#include <osg/Transform> | |
#include <osg/Uniform> | |
#include <osgViewer/Viewer> | |
#include <osg/LineWidth> | |
#include <osg/Point> | |
#include <osg/BlendFunc> | |
#include <osgDB/ReadFile> | |
struct ModelViewProjectionMatrixCallback: public osg::Uniform::Callback | |
{ | |
ModelViewProjectionMatrixCallback(osg::Camera* camera) : | |
_camera(camera) { | |
} | |
virtual void operator()(osg::Uniform* uniform, osg::NodeVisitor* nv) { | |
osg::Matrixd viewMatrix = _camera->getViewMatrix(); | |
osg::Matrixd modelMatrix = osg::computeLocalToWorld(nv->getNodePath()); | |
osg::Matrixd modelViewProjectionMatrix = modelMatrix * viewMatrix * _camera->getProjectionMatrix(); | |
uniform->set(modelViewProjectionMatrix); | |
} | |
osg::Camera* _camera; | |
}; | |
struct ViewportCallback: public osg::Uniform::Callback | |
{ | |
ViewportCallback(osg::Camera* camera) : | |
_camera(camera) { | |
} | |
virtual void operator()(osg::Uniform* uniform, osg::NodeVisitor* /*nv*/) { | |
const osg::Viewport* viewport = _camera->getViewport(); | |
osg::Vec2f viewportVector = osg::Vec2f(viewport->width(), viewport->height()); | |
uniform->set(viewportVector); | |
} | |
osg::Camera* _camera; | |
}; | |
const int OSG_WIDTH = 1280; | |
const int OSG_HEIGHT = 960; | |
osg::Node* createTestScene() | |
{ | |
osg::Vec3Array* vertices = new osg::Vec3Array; | |
osg::Vec4Array* colors = new osg::Vec4Array; | |
vertices->setName("Vertex"); | |
vertices->push_back(osg::Vec3f(0,1,0)); | |
vertices->push_back(osg::Vec3f(1,1,0)); | |
vertices->push_back(osg::Vec3f(1,1,1)); | |
vertices->push_back(osg::Vec3f(0,1,1)); | |
vertices->push_back(osg::Vec3f(0.5,1,1.5)); | |
vertices->push_back(osg::Vec3f(0.5,1,2)); | |
colors->push_back(osg::Vec4(1,0.3,0,1)); | |
osg::ref_ptr<osg::Geometry> geom = new osg::Geometry; | |
geom->addPrimitiveSet(new osg::DrawArrays(GL_LINE_STRIP, 0, vertices->size())); | |
geom->setUseDisplayList(false); | |
geom->setVertexArray(vertices); | |
geom->setColorArray(colors, osg::Array::BIND_OVERALL); | |
osg::ref_ptr<osg::Geode> geode = new osg::Geode; | |
geode->addDrawable(geom.get()); | |
osg::StateSet* state = geode->getOrCreateStateSet(); | |
state->setMode(GL_LIGHTING, osg::StateAttribute::OFF); | |
state->setMode(GL_BLEND, osg::StateAttribute::ON); | |
state->setMode(GL_LINE_SMOOTH, osg::StateAttribute::ON); | |
osg::LineWidth* lw = new osg::LineWidth; | |
lw->setWidth(10.f); | |
state->setAttribute(lw, osg::StateAttribute::ON); | |
osg::BlendFunc* blendfunc = new osg::BlendFunc(); | |
state->setAttributeAndModes(blendfunc, osg::StateAttribute::ON); | |
return geode.release(); | |
} | |
int main(int, char**) | |
{ | |
::SetProcessDPIAware(); | |
osgViewer::Viewer viewer; | |
osg::Camera* camera = viewer.getCamera(); | |
osg::ref_ptr<osg::Group> root = new osg::Group(); | |
osg::Vec3Array* vertices = new osg::Vec3Array; | |
osg::Vec4Array* colors = new osg::Vec4Array; | |
vertices->setName("Vertex"); | |
vertices->push_back(osg::Vec3f(-1,0,0)); | |
vertices->push_back(osg::Vec3f(0,0,0)); | |
vertices->push_back(osg::Vec3f(1,0,0)); | |
vertices->push_back(osg::Vec3f(1,0,1)); | |
vertices->push_back(osg::Vec3f(0,0,0)); | |
vertices->push_back(osg::Vec3f(1,0,0)); | |
vertices->push_back(osg::Vec3f(1,0,1)); | |
vertices->push_back(osg::Vec3f(0,0,1)); | |
vertices->push_back(osg::Vec3f(1,0,0)); | |
vertices->push_back(osg::Vec3f(1,0,1)); | |
vertices->push_back(osg::Vec3f(0,0,1)); | |
vertices->push_back(osg::Vec3f(0.5,0,1.5)); | |
vertices->push_back(osg::Vec3f(1,0,1)); | |
vertices->push_back(osg::Vec3f(0,0,1)); | |
vertices->push_back(osg::Vec3f(0.5,0,1.5)); | |
vertices->push_back(osg::Vec3f(0.5,0,2)); | |
vertices->push_back(osg::Vec3f(0,0,1)); | |
vertices->push_back(osg::Vec3f(0.5,0,1.5)); | |
vertices->push_back(osg::Vec3f(0.5,0,2)); | |
vertices->push_back(osg::Vec3f(0.5,0,3)); | |
colors->setName("Color"); | |
colors->push_back(osg::Vec4f(0.2, 0.9, 1.0, 1)); | |
colors->push_back(osg::Vec4f(0.8, 0.2, 1.0, 1)); | |
colors->push_back(osg::Vec4f(0.0, 0.7, 1.0, 1)); | |
colors->push_back(osg::Vec4f(0.8, 0.1, 1.0, 1)); | |
colors->push_back(osg::Vec4f(0.8, 0.2, 1.0, 1)); | |
colors->push_back(osg::Vec4f(0.0, 0.7, 1.0, 1)); | |
colors->push_back(osg::Vec4f(0.8, 0.1, 1.0, 1)); | |
colors->push_back(osg::Vec4f(0.2, 0.9, 1.0, 1)); | |
colors->push_back(osg::Vec4f(0.0, 0.7, 1.0, 1)); | |
colors->push_back(osg::Vec4f(0.8, 0.1, 1.0, 1)); | |
colors->push_back(osg::Vec4f(0.2, 0.9, 1.0, 1)); | |
colors->push_back(osg::Vec4f(0.2, 0.9, 1.0, 1)); | |
colors->push_back(osg::Vec4f(0.8, 0.2, 1.0, 1)); | |
colors->push_back(osg::Vec4f(0.0, 0.7, 1.0, 1)); | |
colors->push_back(osg::Vec4f(0.8, 0.1, 1.0, 1)); | |
colors->push_back(osg::Vec4f(0.2, 0.9, 1.0, 1)); | |
colors->push_back(osg::Vec4f(0.8, 0.2, 1.0, 1)); | |
colors->push_back(osg::Vec4f(0.0, 0.7, 1.0, 1)); | |
colors->push_back(osg::Vec4f(0.8, 0.1, 1.0, 1)); | |
colors->push_back(osg::Vec4f(0.2, 0.9, 1.0, 1)); | |
// create geometry | |
osg::ref_ptr<osg::Geometry> geom = new osg::Geometry; | |
geom->addPrimitiveSet(new osg::DrawArrays(GL_LINES_ADJACENCY_EXT, 0, vertices->size())); | |
geom->setUseDisplayList(false); | |
// defaults | |
geom->setVertexArray(vertices); | |
geom->setColorArray(colors, osg::Array::BIND_PER_VERTEX); | |
// set attributes | |
geom->setVertexAttribArray(0, vertices, osg::Array::BIND_PER_VERTEX); | |
geom->setVertexAttribArray(1, colors, osg::Array::BIND_PER_VERTEX); | |
// create shader | |
osg::ref_ptr<osg::Program> program = new osg::Program; | |
program->setName("shader"); | |
// program->addShader(new osg::Shader(osg::Shader::VERTEX, vertSource)); | |
osg::ref_ptr<osg::Shader> vertShader = new osg::Shader(osg::Shader::VERTEX); | |
if (!vertShader->loadShaderSourceFromFile("polyline.vert")) | |
std::cerr << "Could not read VERTEX shader from file" << std::endl; | |
program->addShader(vertShader); | |
osg::ref_ptr<osg::Shader> geomShader = new osg::Shader(osg::Shader::GEOMETRY); | |
if (!geomShader->loadShaderSourceFromFile("polyline.geom")) | |
std::cerr << "Could not read GEOMETRY shader from file" << std::endl; | |
program->addShader(geomShader); | |
osg::ref_ptr<osg::Shader> fragShader = new osg::Shader(osg::Shader::FRAGMENT); | |
if (!fragShader->loadShaderSourceFromFile("polyline.frag")) | |
std::cerr << "Could not read FRAGMENT shader from file" << std::endl; | |
program->addShader(fragShader); | |
// program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragSource)); | |
// geode | |
osg::ref_ptr<osg::Geode> geode = new osg::Geode; | |
geode->addDrawable(geom.get()); | |
osg::StateSet* state = geode->getOrCreateStateSet(); | |
state->setAttributeAndModes(program.get(), osg::StateAttribute::ON); | |
// add uniforms | |
osg::Uniform* modelViewProjectionMatrix = new osg::Uniform(osg::Uniform::FLOAT_MAT4, "ModelViewProjectionMatrix"); | |
modelViewProjectionMatrix->setUpdateCallback(new ModelViewProjectionMatrixCallback(camera)); | |
state->addUniform(modelViewProjectionMatrix); | |
osg::Uniform* viewportVector = new osg::Uniform(osg::Uniform::FLOAT_VEC2, "Viewport"); | |
viewportVector->setUpdateCallback(new ViewportCallback(camera)); | |
state->addUniform(viewportVector); | |
float Thickness = 7.0; | |
float miterLimit = 0.75; | |
state->addUniform(new osg::Uniform("Thickness", Thickness)); | |
state->addUniform(new osg::Uniform("MiterLimit", miterLimit)); | |
// state settings | |
state->setMode(GL_LIGHTING, osg::StateAttribute::OFF); | |
state->setMode(GL_BLEND, osg::StateAttribute::ON); | |
state->setMode(GL_LINE_SMOOTH, osg::StateAttribute::ON); | |
osg::LineWidth* lw = new osg::LineWidth; | |
lw->setWidth(10.f); | |
state->setAttribute(lw, osg::StateAttribute::ON); | |
osg::BlendFunc* blendfunc = new osg::BlendFunc(); | |
state->setAttributeAndModes(blendfunc, osg::StateAttribute::ON); | |
// graphics context params | |
osg::DisplaySettings::instance()->setNumMultiSamples(4); // anti aliased shadered lines | |
// scene state run | |
root->addChild(geode.get()); | |
root->addChild(createTestScene()); | |
viewer.setSceneData(root.get()); | |
viewer.setUpViewInWindow(100,100,OSG_WIDTH, OSG_HEIGHT); | |
// viewer.setUpViewOnSingleScreen(0); | |
return viewer.run(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#version 330 | |
in VertexData{ | |
vec2 mTexCoord; | |
vec4 mColor; | |
} VertexIn; | |
const vec4 testColor = vec4(0.3,1,0,1); | |
void main(void) | |
{ | |
gl_FragColor = vec4(VertexIn.mColor.xy, 0.2, 1); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#version 330 | |
uniform float Thickness; | |
uniform vec2 Viewport; | |
uniform float MiterLimit; | |
layout(lines_adjacency) in; | |
layout(triangle_strip, max_vertices = 7) out; | |
in VertexData{ | |
vec4 mColor; | |
} VertexIn[4]; | |
out VertexData{ | |
vec2 mTexCoord; | |
vec4 mColor; | |
} VertexOut; | |
vec2 toScreenSpace(vec4 vertex) | |
{ | |
return vec2( vertex.xy / vertex.w ) * Viewport; | |
} | |
void main(void) | |
{ | |
// 4 points | |
vec4 P0 = gl_in[0].gl_Position; | |
vec4 P1 = gl_in[1].gl_Position; | |
vec4 P2 = gl_in[2].gl_Position; | |
vec4 P3 = gl_in[3].gl_Position; | |
// get the four vertices passed to the shader: | |
vec2 p0 = toScreenSpace( P0 ); // start of previous segment | |
vec2 p1 = toScreenSpace( P1 ); // end of previous segment, start of current segment | |
vec2 p2 = toScreenSpace( P2 ); // end of current segment, start of next segment | |
vec2 p3 = toScreenSpace( P3 ); // end of next segment | |
// perform naive culling | |
vec2 area = Viewport * 1.8; | |
if( p1.x < -area.x || p1.x > area.x ) return; | |
if( p1.y < -area.y || p1.y > area.y ) return; | |
if( p2.x < -area.x || p2.x > area.x ) return; | |
if( p2.y < -area.y || p2.y > area.y ) return; | |
// determine the direction of each of the 3 segments (previous, current, next) | |
vec2 v0 = normalize( p1 - p0 ); | |
vec2 v1 = normalize( p2 - p1 ); | |
vec2 v2 = normalize( p3 - p2 ); | |
// determine the normal of each of the 3 segments (previous, current, next) | |
vec2 n0 = vec2( -v0.y, v0.x ); | |
vec2 n1 = vec2( -v1.y, v1.x ); | |
vec2 n2 = vec2( -v2.y, v2.x ); | |
// determine miter lines by averaging the normals of the 2 segments | |
vec2 miter_a = normalize( n0 + n1 ); // miter at start of current segment | |
vec2 miter_b = normalize( n1 + n2 ); // miter at end of current segment | |
// determine the length of the miter by projecting it onto normal and then inverse it | |
float an1 = dot(miter_a, n1); | |
float bn1 = dot(miter_b, n2); | |
if (an1==0) an1 = 1; | |
if (bn1==0) bn1 = 1; | |
float length_a = Thickness / an1; | |
float length_b = Thickness / bn1; | |
// prevent excessively long miters at sharp corners | |
if( dot( v0, v1 ) < -MiterLimit ) { | |
miter_a = n1; | |
length_a = Thickness; | |
// close the gap | |
if( dot( v0, n1 ) > 0 ) { | |
VertexOut.mTexCoord = vec2( 0, 0 ); | |
VertexOut.mColor = VertexIn[1].mColor; | |
gl_Position = vec4( ( p1 + Thickness * n0 ) / Viewport, 0.0, 1.0 ); | |
EmitVertex(); | |
VertexOut.mTexCoord = vec2( 0, 0 ); | |
VertexOut.mColor = VertexIn[1].mColor; | |
gl_Position = vec4( ( p1 + Thickness * n1 ) / Viewport, 0.0, 1.0 ); | |
EmitVertex(); | |
VertexOut.mTexCoord = vec2( 0, 0.5 ); | |
VertexOut.mColor = VertexIn[1].mColor; | |
gl_Position = vec4( p1 / Viewport, 0.0, 1.0 ); | |
EmitVertex(); | |
EndPrimitive(); | |
} | |
else { | |
VertexOut.mTexCoord = vec2( 0, 1 ); | |
VertexOut.mColor = VertexIn[1].mColor; | |
gl_Position = vec4( ( p1 - Thickness * n1 ) / Viewport, 0.0, 1.0 ); | |
EmitVertex(); | |
VertexOut.mTexCoord = vec2( 0, 1 ); | |
VertexOut.mColor = VertexIn[1].mColor; | |
gl_Position = vec4( ( p1 - Thickness * n0 ) / Viewport, 0.0, 1.0 ); | |
EmitVertex(); | |
VertexOut.mTexCoord = vec2( 0, 0.5 ); | |
VertexOut.mColor = VertexIn[1].mColor; | |
gl_Position = vec4( p1 / Viewport, 0.0, 1.0 ); | |
EmitVertex(); | |
EndPrimitive(); | |
} | |
} | |
if( dot( v1, v2 ) < -MiterLimit ) { | |
miter_b = n1; | |
length_b = Thickness; | |
} | |
// generate the triangle strip | |
VertexOut.mTexCoord = vec2( 0, 0 ); | |
VertexOut.mColor = VertexIn[1].mColor; | |
gl_Position = vec4( ( p1 + length_a * miter_a ) / Viewport, 0.0, 1.0 ); | |
EmitVertex(); | |
VertexOut.mTexCoord = vec2( 0, 1 ); | |
VertexOut.mColor = VertexIn[1].mColor; | |
gl_Position = vec4( ( p1 - length_a * miter_a ) / Viewport, 0.0, 1.0 ); | |
EmitVertex(); | |
VertexOut.mTexCoord = vec2( 0, 0 ); | |
VertexOut.mColor = VertexIn[2].mColor; | |
gl_Position = vec4( ( p2 + length_b * miter_b ) / Viewport, 0.0, 1.0 ); | |
EmitVertex(); | |
VertexOut.mTexCoord = vec2( 0, 1 ); | |
VertexOut.mColor = VertexIn[2].mColor; | |
gl_Position = vec4( ( p2 - length_b * miter_b ) / Viewport, 0.0, 1.0 ); | |
EmitVertex(); | |
EndPrimitive(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#version 330 | |
uniform mat4 ModelViewProjectionMatrix; | |
layout(location = 0) in vec4 Vertex; | |
layout(location = 1) in vec4 Color; | |
out VertexData{ | |
vec4 mColor; | |
} VertexOut; | |
void main(void) | |
{ | |
VertexOut.mColor = Color; | |
gl_Position = ModelViewProjectionMatrix * Vertex; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment