Skip to content

Instantly share code, notes, and snippets.

@vicrucann
Created July 13, 2016 20:09
Show Gist options
  • Save vicrucann/3575301f46ee9702ff7f5af8e4959f56 to your computer and use it in GitHub Desktop.
Save vicrucann/3575301f46ee9702ff7f5af8e4959f56 to your computer and use it in GitHub Desktop.
Similar to the osg-shader-polyline, but with round caps (in development)
#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;
};
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("../osg-shader/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("../osg-shader/stroke.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("../osg-shader/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);
float Thickness = 7.0;
float miterLimit = 0.75;
float baseWidth = 0.008;
float widthAmplitude = 0.005;
state->addUniform(new osg::Uniform("Thickness", Thickness));
osg::Vec2f viewport = osg::Vec2f(OSG_WIDTH, OSG_HEIGHT);
state->addUniform(new osg::Uniform("Viewport", viewport));
state->addUniform(new osg::Uniform("MiterLimit", miterLimit));
state->addUniform(new osg::Uniform("BaseWidth", baseWidth));
state->addUniform(new osg::Uniform("WidthAplitude", widthAmplitude));
// 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);
// 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();
}
#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);
}
#version 330
uniform mat4 ModelViewProjectionMatrix;
uniform float Thickness;
uniform vec2 Viewport;
uniform float MiterLimit;
uniform float BaseWidth;
uniform float WidthAmplitude;
const float pi = 3.14159265;
const float epsilon = 0.0001;
layout(lines_adjacency) in;
layout(triangle_strip, max_vertices = 32) out;
in VertexData{
vec4 mColor;
} VertexIn[4];
out VertexData{
vec2 mTexCoord;
vec4 mColor;
} VertexOut;
void ClipLineSegmentToNearPlane(mat4 MVP, vec4 P0, vec4 P1, vec4 P2, vec4 P3,
out vec4 p0, out vec4 p1, out vec4 p2, out vec4 p3, out bool isCulled)
{
const float nearPlaneDistance = 0.5;
p1 = MVP * P1;
p2 = MVP * P2;
isCulled = false;
float distanceToP1 = p1.z + nearPlaneDistance;
float distanceToP2 = p2.z + nearPlaneDistance;
if ((distanceToP1 * distanceToP2) < 0.0) {
float t = distanceToP1 / (distanceToP1 - distanceToP2);
vec3 modelV = vec3(P1) + t * (vec3(P2) - vec3(P1));
vec4 clipV = MVP * vec4(modelV, 1);
if (distanceToP1 < 0.0) {
p1 = clipV;
p0 = p1;
p3 = MVP * P3;
}
else {
p2 = clipV;
p3 = p2;
p0 = MVP * P0;
}
}
else if (distanceToP1 < 0.0){
isCulled = true;
}
else {
p0 = MVP * P0;
p3 = MVP * P3;
}
}
void halfDiscStrip(vec2 dir, float sign, vec3 center, float radius, vec4 color)
{
const int divs = 8;
const int nps = divs+1;
vec2 ps[nps];
float da = sign*pi/divs;
vec2 rot_x = vec2(cos(da), -sin(da));
vec2 rot_y = vec2(sin(da), cos(da));
int i;
ps[0] = dir;
for(i=1; i<nps; ++i) {
ps[i] = vec2(dot(ps[i-1], rot_x), dot(ps[i-1], rot_y));
}
int j;
for(i=0, j=(nps-1); i<(nps/2); ++i, --j) {
vec2 this_pos = ps[i];
this_pos *= radius;
this_pos += center.xy;
gl_Position = vec4( this_pos, center.z, 1.0);
VertexOut.mColor = color;
EmitVertex();
this_pos = ps[j];
this_pos *= radius;
this_pos += center.xy;
gl_Position = vec4(this_pos, center.z, 1.0);
VertexOut.mColor = color;
EmitVertex();
}
if(nps % 2 == 1) {
vec2 this_pos = ps[nps/2];
this_pos *= radius;
this_pos += center.xy;
gl_Position = vec4(this_pos, center.z, 1.0);
VertexOut.mColor = color;
EmitVertex();
}
}
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;
int i;
vec4 p0;
vec4 p1;
vec4 p2;
vec4 p3;
bool isCulled;
ClipLineSegmentToNearPlane(ModelViewProjectionMatrix, P0, P1, P2, P3, p0, p1, p2, p3, isCulled);
if (isCulled) return;
p0.xyz /= p0.w;
p1.xyz /= p1.w;
p2.xyz /= p2.w;
p3.xyz /= p3.w;
float length_a = BaseWidth + WidthAmplitude * VertexIn[1].mColor.a;
float length_b = BaseWidth + WidthAmplitude * VertexIn[2].mColor.a;
if(p1 == p2){
halfDiscStrip(vec2(1.0, 0.0), 1.0, p2.xyz, length_a, VertexIn[1].mColor);
EndPrimitive();
halfDiscStrip(vec2(1.0, 0.0), -1.0, p2.xyz, length_a, VertexIn[1].mColor);
}
else {
vec2 direction = normalize(p2.xy - p1.xy);
vec2 normal = vec2(direction.y, -direction.x);
vec2 direction_before, direction_after, normal_after;
float a_before, sign_before, recul_before, a_after, sign_after, recul_after;
bool start = false;
bool end = false;
bool u_turn_before = false;
bool u_turn_after = false;
if(p1 != p0)
{
direction_before = normalize(p1.xy - p0.xy);
a_before = acos(clamp(dot(direction, direction_before), -1.0, 1.0));
sign_before = sign(dot(normal, direction_before));
if(sign_before != -1.0 && sign_before != 1.0) sign_before = 1.0;
if(a_before < epsilon)
{
recul_before = 0.0;
}
else if(a_before > pi/2.0)
{
recul_before = 0.0;
u_turn_before = true;
}
else
recul_before = length_a/tan((pi-a_before)/2.0);
}
else
{
direction_before = vec2(0.0, 0.0);
a_before = 0.0;
sign_before = 1.0;
recul_before = 0.0;
start = true;
}
if(p2 != p3)
{
direction_after = normalize(p3.xy - p2.xy);
normal_after = vec2(direction_after.y, -direction_after.x);
a_after = acos(clamp(dot(direction, direction_after), -1.0, 1.0));
sign_after = sign(dot(normal, direction_after));
if(sign_after != -1.0 && sign_after != 1.0) sign_after = 1.0;
if(a_after < epsilon)
{
recul_after = 0.0;
}
else if(a_after > pi/2.0) //u turn
{
u_turn_after = true;
recul_after = 0.0;
}
else
recul_after = length_b/tan((pi-a_after)/2.0);
}
else
{
direction_after = vec2(0.0, 0.0);
normal_after = vec2(0.0, 0.0);
a_after = 0.0;
sign_after = 1.0;
recul_after = 0.0;
end = true;
}
if(start == true)
{
halfDiscStrip(normal, -1.0, p1.xyz, length_a, VertexIn[1].mColor);
EndPrimitive();
gl_Position = vec4(p1.xy - (normal * length_a * sign_after), p1.z, 1.0);
VertexOut.mColor = VertexIn[1].mColor;
EmitVertex();
gl_Position = vec4(p1.xy + (normal * length_a * sign_after), p1.z, 1.0);
VertexOut.mColor = VertexIn[1].mColor;
EmitVertex();
}
else if(u_turn_before == true)
{
gl_Position = vec4(p1.xy - (normal * length_a * sign_after), p1.z, 1.0);
VertexOut.mColor = VertexIn[1].mColor;
EmitVertex();
gl_Position = vec4(p1.xy + (normal * length_a * sign_after), p1.z, 1.0);
VertexOut.mColor = VertexIn[1].mColor;
EmitVertex();
}
else
{
if(recul_before != 0.0)
{
gl_Position = vec4(p1.xy, p1.z, 1.0);
VertexOut.mColor = VertexIn[1].mColor;
EmitVertex();
}
if(sign_before != sign_after)
{
gl_Position = vec4(p1.xy + (normal * length_a * sign_before), p1.z, 1.0);
VertexOut.mColor = VertexIn[1].mColor;
EmitVertex();
gl_Position = vec4(p1.xy - (normal * length_a * sign_before) + direction * recul_before, p1.z, 1.0);
VertexOut.mColor = VertexIn[1].mColor;
EmitVertex();
}
else
{
gl_Position = vec4(p1.xy - (normal * length_a * sign_before) + direction * recul_before, p1.z, 1.0);
VertexOut.mColor = VertexIn[1].mColor;
EmitVertex();
gl_Position = vec4(p1.xy + (normal * length_a * sign_before), p1.z, 1.0);
VertexOut.mColor = VertexIn[1].mColor;
EmitVertex();
}
}
if(end == true)
{
gl_Position = vec4(p2.xy - (normal * length_b * sign_after), p2.z, 1.0);
VertexOut.mColor = VertexIn[2].mColor;
EmitVertex();
gl_Position = vec4(p2.xy + (normal * length_b * sign_after), p2.z, 1.0);
VertexOut.mColor = VertexIn[2].mColor;
EmitVertex();
EndPrimitive();
halfDiscStrip(normal, 1.0, p2.xyz, length_b, VertexIn[2].mColor);
}
else if(u_turn_after == true)
{
gl_Position = vec4(p2.xy - (normal * length_b * sign_after), p2.z, 1.0);
VertexOut.mColor = VertexIn[2].mColor;
EmitVertex();
gl_Position = vec4(p2.xy + (normal * length_b * sign_after), p2.z, 1.0);
VertexOut.mColor = VertexIn[2].mColor;
EmitVertex();
}
else
{
gl_Position = vec4(p2.xy - (normal * length_b * sign_after), p2.z, 1.0);
VertexOut.mColor = VertexIn[2].mColor;
EmitVertex();
gl_Position = vec4(p2.xy + (normal * length_b * sign_after) - (direction * recul_after), p2.z, 1.0);
VertexOut.mColor = VertexIn[2].mColor;
EmitVertex();
if(recul_after != 0.0)
{
gl_Position = vec4(p2.xy, p2.z, 1.0);
VertexOut.mColor = VertexIn[2].mColor;
EmitVertex();
}
}
if(recul_after != 0.0 || u_turn_after)
{
EndPrimitive();
gl_Position = vec4(p2.xy - (normal * length_b * sign_after), p2.z, 1.0);
VertexOut.mColor = VertexIn[2].mColor;
EmitVertex();
float da = -sign_after*a_after/3.0;
vec2 rot_x = vec2(cos(da), -sin(da));
vec2 rot_y = vec2(sin(da), cos(da));
vec2 new_normal1 = vec2(dot((-normal*sign_after), rot_x), dot((-normal*sign_after), rot_y));
gl_Position = vec4(p2.xy + (new_normal1 * length_b), p2.z, 1.0);
VertexOut.mColor = VertexIn[2].mColor;
EmitVertex();
gl_Position = vec4(p2.xy, p2.z, 1.0);
VertexOut.mColor = VertexIn[2].mColor;
EmitVertex();
vec2 new_normal2 = vec2(dot(new_normal1, rot_x), dot(new_normal1, rot_y));
gl_Position = vec4(p2.xy + (new_normal2 * length_b), p2.z, 1.0);
VertexOut.mColor = VertexIn[2].mColor;
EmitVertex();
gl_Position = vec4(p2.xy - (normal_after * length_b * sign_after), p2.z, 1.0);
VertexOut.mColor = VertexIn[2].mColor;
EmitVertex();
}
}
}
#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