经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 软件/图像 » unity » 查看文章
OSG与Shader的结合使用
来源:cnblogs  作者:charlee44  时间:2019/8/29 8:41:19  对本文有异议

1. 概述

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

2. 固定管线着色

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

  1. #include <iostream>
  2. #include <Windows.h>
  3. #include <osgViewer/Viewer>
  4. #include <osgDB/ReadFile>
  5. using namespace std;
  6. int main()
  7. {
  8. osg::ref_ptr<osg::Group> root= new osg::Group();
  9. string osgPath = "D:/Work/OSGBuild/OpenSceneGraph-Data/glider.osg";
  10. osg::Node * node = osgDB::readNodeFile(osgPath);
  11. root->addChild(node);
  12. osgViewer::Viewer viewer;
  13. viewer.setSceneData(root);
  14. viewer.setUpViewInWindow(100, 100, 800, 600);
  15. return viewer.run();
  16. }

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

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

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

  1. #include <iostream>
  2. #include <Windows.h>
  3. #include <osgViewer/Viewer>
  4. #include <osgDB/ReadFile>
  5. using namespace std;
  6. //设置纹理着色
  7. static void ColorShader(osg::ref_ptr<osg::Node> node)
  8. {
  9. const char * vertexShader = {
  10. "void main(void ){\n"
  11. " gl_FrontColor = gl_Color;\n"
  12. " gl_Position = gl_ModelViewProjectionMatrix*gl_Vertex;\n"
  13. "}\n"
  14. };
  15. const char * fragShader = {
  16. "void main(void){\n"
  17. " gl_FragColor = gl_Color;\n"
  18. "}\n"
  19. };
  20. osg::StateSet * ss = node->getOrCreateStateSet();
  21. osg::ref_ptr<osg::Program> program = new osg::Program();
  22. program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragShader));
  23. program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexShader));
  24. ss->setAttributeAndModes(program, osg::StateAttribute::ON);
  25. }
  26. int main()
  27. {
  28. osg::ref_ptr<osg::Group> root= new osg::Group();
  29. string osgPath = "D:/Work/OSGBuild/OpenSceneGraph-Data/glider.osg";
  30. osg::Node * node = osgDB::readNodeFile(osgPath);
  31. root->addChild(node);
  32. ColorShader(node);
  33. osgViewer::Viewer viewer;
  34. viewer.setSceneData(root);
  35. viewer.setUpViewInWindow(100, 100, 800, 600);
  36. return viewer.run();
  37. }

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

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

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

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

3. 纹理着色

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

  1. #include <iostream>
  2. #include <Windows.h>
  3. #include <osgViewer/Viewer>
  4. #include <osgDB/ReadFile>
  5. using namespace std;
  6. int main()
  7. {
  8. osg::ref_ptr<osg::Group> root= new osg::Group();
  9. string osgPath = "D:/Data/scene/Dayanta_OSGB/Data/MultiFoderReader.osgb";
  10. osg::Node * node = osgDB::readNodeFile(osgPath);
  11. root->addChild(node);
  12. osgViewer::Viewer viewer;
  13. viewer.setSceneData(root);
  14. viewer.setUpViewInWindow(100, 100, 800, 600);
  15. return viewer.run();
  16. }

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

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

  1. //设置纹理着色
  2. static void TextureShader(osg::ref_ptr<osg::Node> node)
  3. {
  4. const char * vertexShader = {
  5. "void main(void ){\n"
  6. " gl_TexCoord[0] = gl_MultiTexCoord0;\n"
  7. " gl_Position = gl_ModelViewProjectionMatrix*gl_Vertex;\n"
  8. "}\n"
  9. };
  10. const char * fragShader = {
  11. "uniform sampler2D baseTexture;\n"
  12. "void main(void){\n"
  13. " vec2 coord = gl_TexCoord[0].xy;\n"
  14. " vec4 C = texture2D(baseTexture, coord)\n;"
  15. " gl_FragColor = C;\n"
  16. "}\n"
  17. };
  18. osg::StateSet * ss = node->getOrCreateStateSet();
  19. osg::ref_ptr<osg::Program> program = new osg::Program();
  20. program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragShader));
  21. program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexShader));
  22. ss->setAttributeAndModes(program, osg::StateAttribute::ON);
  23. }
  24. int main()
  25. {
  26. osg::ref_ptr<osg::Group> root= new osg::Group();
  27. string osgPath = "D:/Data/scene/Dayanta_OSGB/Data/MultiFoderReader.osgb";
  28. osg::Node * node = osgDB::readNodeFile(osgPath);
  29. root->addChild(node);
  30. TextureShader(node);
  31. osgViewer::Viewer viewer;
  32. viewer.setSceneData(root);
  33. viewer.setUpViewInWindow(100, 100, 800, 600);
  34. return viewer.run();
  35. }

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

4. 参考

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

原文链接:http://www.cnblogs.com/charlee44/p/11427066.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号