bkmeneguello
7/21/2013 - 12:49 AM

OpenSceneGraph Shader 4.00

OpenSceneGraph Shader 4.00

#include <osg/ArgumentParser>
#include <osg/Array>
#include <osg/Camera>
#include <osg/Drawable>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/Group>
#include <osg/Light>
#include <osg/Matrixd>
#include <osg/MixinVector>
#include <osg/Node>
#include <osg/NodeVisitor>
#include <osg/Object>
#include <osg/PrimitiveSet>
#include <osg/Program>
#include <osg/Shader>
#include <osg/StateAttribute>
#include <osg/StateSet>
#include <osg/Transform>
#include <osg/Uniform>
#include <osg/Vec3f>
#include <osg/Vec4f>
#include <osg/View>
#include <osgDB/ReadFile>
#include <osgGA/OrbitManipulator>
#include <osgGA/StateSetManipulator>
#include <osgViewer/View>
#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>

struct ModelViewMatrixCallback: public osg::Uniform::Callback {
	ModelViewMatrixCallback(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());
		uniform->set(modelMatrix * viewMatrix);
	}

	osg::Camera* _camera;
};

struct NormalMatrixCallback: public osg::Uniform::Callback {
	NormalMatrixCallback(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 modelViewMatrix = modelMatrix * viewMatrix;

		modelViewMatrix.setTrans(0.0, 0.0, 0.0);

		osg::Matrixd inverse;
		inverse.invert(modelViewMatrix);

		osg::Matrix3 normalMatrix(
				inverse(0,0), inverse(1,0), inverse(2,0),
				inverse(0,1), inverse(1,1), inverse(2,1),
				inverse(0,2), inverse(1,2), inverse(2,2));

		uniform->set(normalMatrix);
	}

	osg::Camera* _camera;
};

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;
};

int main(int argc, char** argv) {
	osg::ArgumentParser arguments(&argc, argv);
	osgViewer::Viewer* viewer = new osgViewer::Viewer(arguments);
	osg::Camera* camera = viewer->getCamera();
	viewer->setCameraManipulator(new osgGA::OrbitManipulator());
	osgGA::StateSetManipulator* stateSet = new osgGA::StateSetManipulator(camera->getOrCreateStateSet());
	viewer->addEventHandler(stateSet);
	viewer->addEventHandler(new osgViewer::StatsHandler);
	viewer->addEventHandler(new osgViewer::WindowSizeHandler);

	osg::Group* root = new osg::Group();

	osg::Vec3Array& vertex = *(new osg::Vec3Array(4));
	osg::Vec3Array& normal = *(new osg::Vec3Array(1));
	osg::Vec4Array& color = *(new osg::Vec4Array(4));

	vertex.setName("Vertex");
	vertex[0].set(0,0,0);
	vertex[1].set(1,0,0);
	vertex[2].set(1,0,1);
	vertex[3].set(0,0,1);

	normal.setName("Normal");
	normal[0].set(0,-1,0);

	color.setName("Color");
	color[0].set(1,0,0,1);
	color[1].set(0,1,0,1);
	color[2].set(0,0,1,1);
	color[3].set(1,0,1,1);

	osg::Geometry *geom = new osg::Geometry;
	geom->setUseDisplayList(false);

	geom->setVertexAttribArray(0, &vertex);
	geom->setVertexAttribNormalize(0, false);
	geom->setVertexAttribBinding(0, osg::Geometry::BIND_PER_VERTEX);

	geom->setVertexAttribArray(1, &normal);
	geom->setVertexAttribNormalize(1, true);
	geom->setVertexAttribBinding(1, osg::Geometry::BIND_OVERALL);

	geom->setVertexAttribArray(2, &color);
	geom->setVertexAttribNormalize(2, false);
	geom->setVertexAttribBinding(2, osg::Geometry::BIND_PER_VERTEX);

	geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4));

	osg::Program* program = new osg::Program;
	program->setName("shader");
	program->addShader(osgDB::readShaderFile(osg::Shader::VERTEX, "test.vert"));
	program->addShader(osgDB::readShaderFile(osg::Shader::FRAGMENT, "test.frag"));

	osg::Geode* geode = new osg::Geode;
	geode->addDrawable(geom);

	osg::StateSet* state = geode->getOrCreateStateSet();
	state->setAttributeAndModes(program, osg::StateAttribute::ON);

	osg::Uniform* modelViewMatrix = new osg::Uniform(osg::Uniform::FLOAT_MAT4, "ModelViewMatrix");
	modelViewMatrix->setUpdateCallback(new ModelViewMatrixCallback(camera));
	state->addUniform(modelViewMatrix);

	osg::Uniform* normalMatrix = new osg::Uniform(osg::Uniform::FLOAT_MAT3, "NormalMatrix");
	normalMatrix->setUpdateCallback(new NormalMatrixCallback(camera));
	state->addUniform(normalMatrix);

	state->addUniform(new osg::Uniform("ProjectionMatrix", camera->getProjectionMatrix()));

	osg::Uniform* modelViewProjectionMatrix = new osg::Uniform(osg::Uniform::FLOAT_MAT4, "ModelViewProjectionMatrix");
	modelViewProjectionMatrix->setUpdateCallback(new ModelViewProjectionMatrixCallback(camera));
	state->addUniform(modelViewProjectionMatrix);

	state->addUniform(new osg::Uniform("LightPosition", viewer->getLight()->getPosition()));
	state->addUniform(new osg::Uniform("DiffuseColor", osg::Vec3f(1, 1, 0)));
	state->addUniform(new osg::Uniform("LightIntensity", osg::Vec3f(.5, .5, 0)));

	root->addChild(geode);

	viewer->setSceneData(root);

	while(!viewer->done()) {
		viewer->frame();
	}

	return 0;
}
#version 400

in vec3 EyeLightIntensity;
layout(location = 0) out vec4 FragColor;

void main(void) {
	FragColor = vec4(EyeLightIntensity, 1.0);
}
#version 400

uniform mat4 ModelViewMatrix;
uniform mat3 NormalMatrix;
uniform mat4 ProjectionMatrix;
uniform mat4 ModelViewProjectionMatrix;

uniform vec4 LightPosition; // Light position in eye coords.
uniform vec3 DiffuseColor; // Diffuse reflectivity
uniform vec3 LightIntensity; // Light source intensity

layout(location = 0) in vec4 Vertex;
layout(location = 1) in vec3 Normal;
layout(location = 2) in vec4 Color;

out vec3 EyeLightIntensity;

void main(void) {
	// Convert normal and position to eye coords
	vec3 tnorm = normalize(NormalMatrix * Normal);
	vec4 eyeCoords = ModelViewMatrix * Vertex;
	vec3 s = normalize(vec3(LightPosition - eyeCoords));
	// The diffuse shading equation
	EyeLightIntensity = LightIntensity * DiffuseColor * max(dot(s, tnorm), 0);
	//LightIntensity = vec3(1,0,1) * vec3(1,1,1) * max(dot(s, tnorm), 0);
	//LightIntensity = Color * max(dot(s, tnorm), 0);
	// Convert position to clip coordinates and pass along
	gl_Position = ModelViewProjectionMatrix * Vertex;
}