首页 > 技术文章 > osg着色器uniform回调实现高亮部分闪烁效果的实例分析

airduce 2018-11-28 17:09 原文

效果:牛身上圈圈里的颜色在闪烁

代码:

 1 #include <osg/Program>
 2 #include <osgDB/ReadFile>
 3 #include <osgViewer/Viewer>
 4 
 5 static const char* vertSource = {
 6     "varying vec3 normal;\n"//易变量 用于着色器之间的传值
 7     "void main()\n"
 8     "{\n"
 9     "    normal = normalize(gl_NormalMatrix * gl_Normal);\n" //把法线向量从物体空间转化到视觉空间。
10     "    gl_Position = ftransform();\n" //相当于 gl_Position = ModelViewProjectionMatrix * gl_Vertex,
11                                                 //模型视图投影矩阵与空间顶点位置相乘,得到裁剪空间顶点位置。
12     "}\n"
13 };
14 
15 static const char* fragSource = {
16     "uniform vec4 mainColor;\n"  //外面程序输入的颜色
17     "varying vec3 normal;\n"    //上面的顶点着色器传的法线
18     "void main()\n"
19     "{\n"
20     "    float intensity = dot(vec3(gl_LightSource[0].position), normal);\n" //计算光照位置与法线的点积,为什么这么做,知道的朋友不吝赐教下。
21                                                                             //按照我的理解就是计算了一下亮度值。
22     //给输出的颜色赋值
23     "    if (intensity > 0.95) gl_FragColor = mainColor;\n" //如果这个值大于0.95,则输出颜色为mainColor,而uniform回调中每帧在来回改这个值,所
24                                                             //以这一部分会出现闪烁的效果。
25     "    else if (intensity > 0.5) gl_FragColor = vec4(0.6,0.3,0.3,1.0);\n"
26     "    else if (intensity > 0.25) gl_FragColor = vec4(0.4,0.2,0.2,1.0);\n"
27     "    else gl_FragColor = vec4(0.2,0.1,0.1,1.0);\n"
28     "}\n"
29 };
30 
31 
32 /* 一直变量uniform回调类,主要用于每帧更新着色器中的用户数据,从而改变渲染的行为和输出结果。     */
33 
34 
35 class ColorCallback : public osg::Uniform::Callback
36 {
37 public:
38     ColorCallback() : _incRed(false) {}
39     
40     virtual void operator()( osg::Uniform* uniform, osg::NodeVisitor* nv )
41     {
42         if ( !uniform ) return;
43         
44         osg::Vec4 color;
45         uniform->get( color );//获取通过uniform 设置进去的值mainColor
46         
47         if ( _incRed==true )//3、如果r减到0呢,就给他一直加。
48         {
49             if ( color.x()<1.0 ) color.x() += 0.1;
50             else _incRed = false;//4、如果加到1就给他再减。
51         }
52         else
53         {
54             if ( color.x()>0.0 ) color.x() -= 0.1;//1、如果RGB中的r分量大于0,则一直减小。
55             else _incRed = true;// 2、r减到0了。
56         }
57         uniform->set( color );
58     }
59 
60 protected:
61     bool _incRed;
62 };
63 
64 void createShaders( osg::StateSet& ss )
65 {
66     osg::ref_ptr<osg::Shader> vertShader = new osg::Shader( osg::Shader::VERTEX, vertSource );
67     osg::ref_ptr<osg::Shader> fragShader = new osg::Shader( osg::Shader::FRAGMENT, fragSource );
68     
69     osg::ref_ptr<osg::Program> program = new osg::Program;
70     program->addShader( vertShader.get() );
71     program->addShader( fragShader.get() );
72     
73     osg::ref_ptr<osg::Uniform> mainColor = new osg::Uniform( "mainColor", osg::Vec4(0.5,0.5,0.5,1.0) );//这个部分的颜色是闪烁部分的颜色值。
74     mainColor->setUpdateCallback( new ColorCallback );
75     
76     ss.addUniform( mainColor.get() );
77     ss.setAttributeAndModes( program.get() );
78 }
79 
80 int main( int argc, char** argv )
81 {
82     osg::ArgumentParser arguments( &argc, argv );
83     osg::Node* model = osgDB::readNodeFiles( arguments );
84     if ( !model ) model = osgDB::readNodeFile( "cow.osg" );
85     
86     createShaders( *(model->getOrCreateStateSet()) );
87     
88     osgViewer::Viewer viewer;
89     viewer.setSceneData( model );
90     viewer.setUpViewInWindow(20,20,600,600);
91     return viewer.run();
92 }

 

推荐阅读