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 ){\n"
" gl_FrontColor = gl_Color;\n"
" gl_Position = gl_ModelViewProjectionMatrix*gl_Vertex;\n"
"}\n"
}; const char * fragShader = {
"void main(void){\n"
" gl_FragColor = gl_Color;\n"
"}\n"
}; 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 ){\n"
" gl_TexCoord[0] = gl_MultiTexCoord0;\n"
" gl_Position = gl_ModelViewProjectionMatrix*gl_Vertex;\n"
"}\n"
}; const char * fragShader = {
"uniform sampler2D baseTexture;\n"
"void main(void){\n"
" vec2 coord = gl_TexCoord[0].xy;\n"
" vec4 C = texture2D(baseTexture, coord)\n;"
" gl_FragColor = C;\n"
"}\n"
}; 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 纹理贴图

OSG与Shader的结合使用的更多相关文章

  1. osg使用shader动态修改纹理坐标

    #include <osg/Node> #include <osg/Geometry> #include <osg/Notify> #include <osg ...

  2. OSG3.4内置Examples解析【目录】

    opengl渲染管线 从整体上解读OpenGL的渲染流程 一 从整体上解读OpenGL的渲染流程 二 osg与animate相关示例解析 OSG3.4内置Examples(osganimate)解析 ...

  3. [OSG]如何用Shader得到物体的世界坐标

    来自:http://www.cnblogs.com/hesicong/archive/2008/05/27/1208312.html 最近群里面有个朋友问我关于如何得到OpenGL世界坐标的问题,当时 ...

  4. osg内置shader变量

    uniform int osg_FrameNumber:当前OSG程序运行的帧数: uniform float osg_FrameTime:当前OSG程序的运行总时间: uniform float o ...

  5. osg Shader 着色器

    #ifdef _WIN32 #include <Windows.h> #endif // _WIN32 #include <osg/Group> #include <os ...

  6. osg shader 相机观察矩阵逆矩阵 求顶点世界坐标

    uniform mat4 osg_ViewMatrixInverse;//osg内置uniform void main() { vec4 posWorld = osg_ViewMatrixInvers ...

  7. [比较老的文章]三维渲染引擎 OGRE 与 OSG 的比较综述

    1 .引言随着计算机可视化.虚拟现实技术的飞速发展,人们对实时真实感渲染以及场景复杂度提出了更高的要求.传统的直接使用底层图形接口如OpenGL.DirectX开发图形应用的模式越来越暴露出开发复杂性 ...

  8. [OSG]OSG例子程序简介

    1.example_osganimate一)演示了路径动画的使用(AnimationPath.AnimationPathCallback),路径动画回调可以作用在Camera.CameraView.M ...

  9. osg实例介绍

    osg实例介绍 转自:http://blog.csdn.net/yungis/article/list/1 [原]osgmotionblur例子 该例子演示了运动模糊的效果.一下内容是转自网上的:原理 ...

随机推荐

  1. hdu6383 p1m2(二分答案)

    p1m2 题目传送门 解题思路 因为x都是非负数,且每一次操作其实就是把总和减少了1,所以可以得出最后都可以到达稳定.最后稳定的数的下界是0,最大也不会超过其初始数的最大值,所以可以用二分答案来求解. ...

  2. 《VR入门系列教程》之8---GearVR

    高端移动虚拟现实设备---三星GearVR     Oculus Rift也许是虚拟现实头显的典范,但是它还是存在许多问题.首先,它需要基于一个具有强大图形计算能力的计算机,而使用一般的笔记本.苹果A ...

  3. Codeforces比赛注意事项(英语比较好,能翻译题目的可以跳过此文章)

    由题目可知,这篇文章是讲翻译文章的. 当然不是教英语啦 其实cf的比赛对于本蒟蒻最大的挑战就是翻译题目啦 所以我比赛时只能靠各种翻译器去无耻地翻译,然后读中文. 目前较好的翻译器有:百度,谷歌,有道. ...

  4. python requests、xpath爬虫增加博客访问量

    这是一个分析IP代理网站,通过代理网站提供的ip去访问CSDN博客,达到以不同ip访同一博客的目的,以娱乐为主,大家可以去玩一下. 首先,准备工作,设置User-Agent: #1.headers h ...

  5. JQuery第一章js 上机+课后

    =============上机1 包含字母   <!DOCTYPE html>   <html>   <head>   <title>sj1.html& ...

  6. 0 Spark完成WordCount操作

    先看下结果: pom.xml: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http ...

  7. java并发笔记之四synchronized 锁的膨胀过程(锁的升级过程)深入剖析

    警告⚠️:本文耗时很长,先做好心理准备,建议PC端浏览器浏览效果更佳. 本篇我们讲通过大量实例代码及hotspot源码分析偏向锁(批量重偏向.批量撤销).轻量级锁.重量级锁及锁的膨胀过程(也就是锁的升 ...

  8. 有容云-【原理】Docker存储驱动之AUFS

    编者按:今天聊一聊Docker的Image(镜像)与Container(容器)的存储以及存储驱动之AUFS.   Docker存储驱动简介 Docker内置多种存储驱动,每种存储驱动都是基于Linux ...

  9. jquery EasyUi 添加节点、展开所有节点、默认选中第一个节点

    感觉easyUi 的树用起来不如 Ext 的树方便,首先,root节点不太好自定义, 异步加载时,只能通过后台判断生成root节点,但是这样一来有一个问题,就是第一次访问界面时, 树的初始化比较慢,大 ...

  10. java-web调用后台下载方法

    后台下载指定文件必定会用到流, 无论使用poi还是使用jxl导出excel都需要用到流一种是outputstrean,另一种fileoutputstream第一种:如果想要弹出保存的提示框必须加入下列 ...