zoukankan      html  css  js  c++  java
  • OSG与Shader的结合使用

    1. 概述

    以往在OpenGL中学习渲染管线的时候,是依次按照申请数据、传送缓冲区、顶点着色器、片元着色器这几个步骤编程的。OSG是OpenGL的一些顶层的封装,使用shader的时候看不到这些步骤了,所以有点不习惯。这里我总结了两个最简单的例子。

    2. 固定管线着色

    OSG一个最简单的示例是展示自带的数据glider.osg:

    #include <iostream>
    #include <Windows.h>
    
    #include <osgViewer/Viewer>
    #include <osgDB/ReadFile>
    
    using namespace std;
    
    int main()
    {
    	osg::ref_ptr<osg::Group> root= new osg::Group();
    
    	string osgPath = "D:/Work/OSGBuild/OpenSceneGraph-Data/glider.osg";
    	osg::Node * node = osgDB::readNodeFile(osgPath);
    	root->addChild(node);
    	
    	osgViewer::Viewer viewer;
    	viewer.setSceneData(root);
    	viewer.setUpViewInWindow(100, 100, 800, 600);
    	return viewer.run();
    }
    

    显示的结果是一个简单的滑翔机:

    用文本的方式打开glider.osg这个数据,里面记录的是其顶点信息:

    这个数据应该是通过固定管线渲染出来的,那么可以为这个场景加入Shader:

    #include <iostream>
    #include <Windows.h>
    
    #include <osgViewer/Viewer>
    #include <osgDB/ReadFile>
    
    using namespace std;
    
    //设置纹理着色
    static void ColorShader(osg::ref_ptr<osg::Node> node)
    {
    	const char * vertexShader = {
    		"void main(void ){
    "
    		"   gl_FrontColor = gl_Color;
    "
    		"   gl_Position = gl_ModelViewProjectionMatrix*gl_Vertex;
    "
    		"}
    "
    	};
    
    	const char * fragShader = {
    		"void main(void){
    "
    		"	gl_FragColor = gl_Color;
    "
    		"}
    "
    	};
    
    	osg::StateSet * ss = node->getOrCreateStateSet();
    	osg::ref_ptr<osg::Program> program = new  osg::Program();
    	program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragShader));
    	program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexShader));
    	ss->setAttributeAndModes(program, osg::StateAttribute::ON);
    }
    
    int main()
    {
    	osg::ref_ptr<osg::Group> root= new osg::Group();
    
    	string osgPath = "D:/Work/OSGBuild/OpenSceneGraph-Data/glider.osg";
    	osg::Node * node = osgDB::readNodeFile(osgPath);
    	root->addChild(node);
    	
    	ColorShader(node);
    
    	osgViewer::Viewer viewer;
    	viewer.setSceneData(root);
    	viewer.setUpViewInWindow(100, 100, 800, 600);
    	return viewer.run();
    }
    

    这段着色器代码是什么意思呢?其实很简单,当使用固定管线的glColor函数后,该颜色值就以作为内置gl_Color变量传入顶点着色器, 顶点着色器计算通过gl_FontColor和gl_BackColor保存正面和反面的值;而继续传入到片元着色器之后,gl_Color则会变成一个由FontColor和BackColor插值计算出来的变量。最终gl_FragColor接受到的就是固定管线渲染得到的值。运行的结果如下:

    最终的结果与之前的结果有所差异,这是osgViewer的默认场景中是有灯光效果的,可编程管线的渲染效果覆盖了固定管线的效果。可以在之前固定管线渲染的例子中加入一句代码

    root->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE);
    

    去除光照效果,两者的渲染效果就完全一致了。

    3. 纹理着色

    另一个例子是通过OSG加载一个带纹理的OSGB模型:

    #include <iostream>
    #include <Windows.h>
    
    #include <osgViewer/Viewer>
    #include <osgDB/ReadFile>
    
    using namespace std;
    
    int main()
    {
    	osg::ref_ptr<osg::Group> root= new osg::Group();
    
    	string osgPath = "D:/Data/scene/Dayanta_OSGB/Data/MultiFoderReader.osgb";
    	osg::Node * node = osgDB::readNodeFile(osgPath);
    	root->addChild(node);
    	
    	osgViewer::Viewer viewer;
    	viewer.setSceneData(root);
    	viewer.setUpViewInWindow(100, 100, 800, 600);
    	return viewer.run();
    }
    

    运行结果会发现某些视角下场景发暗,这同样也是由于场景中的默认光线造成的:

    采取同样的方式,通过shader覆盖固定管线的渲染效果:

    //设置纹理着色
    static void TextureShader(osg::ref_ptr<osg::Node> node)
    {
    	const char * vertexShader = {
    		"void main(void ){
    "
    		"   gl_TexCoord[0] = gl_MultiTexCoord0;
    "
    		"   gl_Position = gl_ModelViewProjectionMatrix*gl_Vertex;
    "
    		"}
    "
    	};
    
    	const char * fragShader = {
    		"uniform sampler2D baseTexture;
    "
    		"void main(void){
    "
    		"   vec2 coord = gl_TexCoord[0].xy;
    "
    		"   vec4 C = texture2D(baseTexture, coord)
    ;"
    		"	gl_FragColor = C;
    "
    		"}
    "
    	};
    
    	osg::StateSet * ss = node->getOrCreateStateSet();
    	osg::ref_ptr<osg::Program> program = new  osg::Program();
    	program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragShader));
    	program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexShader));
    	ss->setAttributeAndModes(program, osg::StateAttribute::ON);
    }
    
    int main()
    {
    	osg::ref_ptr<osg::Group> root= new osg::Group();
    
    	string osgPath = "D:/Data/scene/Dayanta_OSGB/Data/MultiFoderReader.osgb";
    	osg::Node * node = osgDB::readNodeFile(osgPath);
    	root->addChild(node);
    	
    	TextureShader(node);
    
    	osgViewer::Viewer viewer;
    	viewer.setSceneData(root);
    	viewer.setUpViewInWindow(100, 100, 800, 600);
    	return viewer.run();
    }
    

    这段shader代码也比较简单,在顶点着色器中,gl_MultiTexCoord0表示在启用多重纹理时的0号纹理单元的坐标顶点,将其保存在预先定义的纹理坐标gl_TexCoord[0]中。gl_TexCoord[0]经过插值后传入片元着色器,通过自定义的纹理单元变量sampler2D baseTexture,使用texture2D函数获取像素值。最终的渲染效果如下:

    4. 参考

    [1].GLSL下几个简单的Shader
    [2].GLSL 纹理贴图

  • 相关阅读:
    hdu 5036 概率+bitset
    hdu 5037 周期优化
    hdu 5038 求出现次数最多的grade
    hdu 5040 bfs
    hdu 5045 N个人做M道题的正确率
    hdu 5046 二分+DLX模板
    hdu 5047 大数找规律
    c:set注意事项
    It is indirectly referenced from required .class files(导入项目报错原因与解决方法)
    oracle-01722,函数subtr,instr
  • 原文地址:https://www.cnblogs.com/charlee44/p/11427066.html
Copyright © 2011-2022 走看看