上篇的代码仅仅是将图形显示,并通过gl_FragColor=vec4(0.4,0.4,0.8,1.0),简单粗暴的上色,其实在createNode()中创建四边
形的时候有创建了几何体的纹理坐标、法线坐标和颜色坐标。下面分别讲颜色的加载和纹理的加载。
1.颜色的加载
颜色的加载有两种方式,一种是通过vertext shader的内建变量gl_Color直接来加载,另外一种是将颜色信息通过attribute传递到
shader里边。如下所示:
(1)通过vertext shader的内建变量gl_Color
vertext shader
1
2 3 4 5 6 |
static
const
char gVertexShader[] =
"varying vec4 col; \n" "void main() { \n" " col = gl_Color; \n" " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; \n" "} \n"; |
fragment shader
1
2 3 4 5 |
static
const
char gFragmentShader[] =
"varying mediump vec4 col; \n" "void main() { \n" " gl_FragColor = col; \n" "} \n"; |
修改createNode()
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
//创建一个四边形节点 osg::ref_ptr<osg::Node> OsgMainApp::createNode() { //创建一个叶节点对象 osg::ref_ptr<osg::Geode> geode = new osg::Geode(); //创建一个几何体对象 osg::ref_ptr<osg::Geometry> geom = new osg::Geometry(); //添加顶点数据 注意顶点的添加顺序是逆时针 osg::ref_ptr<osg::Vec3Array> v = new osg::Vec3Array(); //添加数据 v->push_back(osg::Vec3( 0, 0, 0)); v->push_back(osg::Vec3( 1, 0, 0)); v->push_back(osg::Vec3( 1, 0, 1)); v->push_back(osg::Vec3( 0, 0, 1)); //设置顶点数据 geom->setVertexArray(v.get()); //创建纹理订点数据 osg::ref_ptr<osg::Vec2Array> vt = new osg::Vec2Array(); //添加纹理坐标 vt->push_back(osg::Vec2( 0, 0)); vt->push_back(osg::Vec2( 1, 0)); vt->push_back(osg::Vec2( 1, 1)); vt->push_back(osg::Vec2( 0, 1)); //设置纹理坐标 geom->setTexCoordArray( 0, vt.get()); //创建颜色数组 osg::ref_ptr<osg::Vec4Array> vc = new osg::Vec4Array(); //添加数据 vc->push_back(osg::Vec4( 1, 0, 0, 1)); vc->push_back(osg::Vec4( 0, 1, 0, 1)); vc->push_back(osg::Vec4( 0, 0, 1, 1)); vc->push_back(osg::Vec4( 1, 1, 0, 1)); //设置颜色数组 geom->setColorArray(vc.get()); //设置颜色的绑定方式为单个顶点 geom->setColorBinding(osg::Geometry::BIND_PER_VERTEX); //创建法线数组 osg::ref_ptr<osg::Vec3Array> nc = new osg::Vec3Array(); //添加法线 nc->push_back(osg::Vec3( 0, - 1, 0)); //设置法线 geom->setNormalArray(nc.get()); //设置法绑定为全部顶点 geom->setNormalBinding(osg::Geometry::BIND_OVERALL); //添加图元 geom->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4)); //添加到叶子节点 geode->addDrawable(geom.get()); osg::StateSet* stateset = new osg::StateSet; return geode.get(); } |
(2)将颜色信息通过attribute传递到shader里边
vertext shader
1
2 3 4 5 6 7 |
static
const
char gVertexShader[] =
"attribute vec4 a_col; \n" "varying vec4 col; \n" "void main() { \n" " col = a_col; \n" " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; \n" "} \n"; |
fragment shader代码
1
2 3 4 5 6 |
static const char gFragmentShader[] = "varying mediump vec4 col; \n" "void main() { \n" " gl_FragColor = col; \n" "} \n"; |
修改createNode()
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
//创建一个四边形节点 osg::ref_ptr<osg::Node> OsgMainApp::createNode() { //创建一个叶节点对象 osg::ref_ptr<osg::Geode> geode = new osg::Geode(); //创建一个几何体对象 osg::ref_ptr<osg::Geometry> geom = new osg::Geometry(); //添加顶点数据 注意顶点的添加顺序是逆时针 osg::ref_ptr<osg::Vec3Array> v = new osg::Vec3Array(); //添加数据 v->push_back(osg::Vec3( 0, 0, 0)); v->push_back(osg::Vec3( 1, 0, 0)); v->push_back(osg::Vec3( 1, 0, 1)); v->push_back(osg::Vec3( 0, 0, 1)); //设置顶点数据 geom->setVertexArray(v.get()); //创建纹理订点数据 osg::ref_ptr<osg::Vec2Array> vt = new osg::Vec2Array(); //添加纹理坐标 vt->push_back(osg::Vec2( 0, 0)); vt->push_back(osg::Vec2( 1, 0)); vt->push_back(osg::Vec2( 1, 1)); vt->push_back(osg::Vec2( 0, 1)); //设置纹理坐标 geom->setTexCoordArray( 0, vt.get()); //创建颜色数组 osg::ref_ptr<osg::Vec4Array> vc = new osg::Vec4Array(); //添加数据 vc->push_back(osg::Vec4( 1, 0, 0, 1)); vc->push_back(osg::Vec4( 0, 1, 0, 1)); vc->push_back(osg::Vec4( 0, 0, 1, 1)); vc->push_back(osg::Vec4( 1, 1, 0, 1)); //设置颜色的绑定方式为单个顶点 //geom->setVertexAttribBinding(1, osg::Geometry::BIND_PER_VERTEX); //geom->setVertexAttribArray(1, vc.get());//颜色的地址//不要用0,2,3 //创建法线数组 osg::ref_ptr<osg::Vec3Array> nc = new osg::Vec3Array(); //添加法线 nc->push_back(osg::Vec3( 0, - 1, 0)); //设置法线 geom->setNormalArray(nc.get()); //设置法绑定为全部顶点 geom->setNormalBinding(osg::Geometry::BIND_OVERALL); //添加图元 geom->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4)); //添加到叶子节点 geode->addDrawable(geom.get()); osg::StateSet* stateset = new osg::StateSet; return geode.get(); } |
此外还得在loadModels()中的Program将颜色的地址传入
1
2 3 4 |
prog->addShader(vshader); prog->addShader(fshader); prog->addBindAttribLocation( "a_col", 1); |
运行结果
2.纹理的加载
由于之前的android,mk 中没有将jpeg的库引入,故要正确加载纹理,必须在android.mk加上-ljpeg 和 -losgdb_jpeg纹理的加
载是通过OSG中的Uniform变量来加载,注意要在sdcard中的osg文件夹放入texture.jpg文件。
vertext shader
1
2 3 4 5 6 |
static
const
char gVertexShader[] =
"varying vec2 v_texCoord; \n" "void main() { \n" " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; \n" " v_texCoord = gl_MultiTexCoord0.xy; \n" "} \n"; |
fragment shader
1
2 3 4 5 6 |
static
const
char gFragmentShader[] =
"varying mediump vec2 v_texCoord; \n" "uniform sampler2D sam; \n" "void main() { \n" " gl_FragColor = texture2D(sam, v_texCoord); \n" "} \n"; |
修改createNode()
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
//创建一个四边形节点 osg::ref_ptr<osg::Node> OsgMainApp::createNode() { //创建一个叶节点对象 osg::ref_ptr<osg::Geode> geode = new osg::Geode(); //创建一个几何体对象 osg::ref_ptr<osg::Geometry> geom = new osg::Geometry(); //添加顶点数据 注意顶点的添加顺序是逆时针 osg::ref_ptr<osg::Vec3Array> v = new osg::Vec3Array(); //添加数据 v->push_back(osg::Vec3( 0, 0, 0)); v->push_back(osg::Vec3( 1, 0, 0)); v->push_back(osg::Vec3( 1, 0, 1)); v->push_back(osg::Vec3( 0, 0, 1)); //设置顶点数据 geom->setVertexArray(v.get()); //创建纹理订点数据 osg::ref_ptr<osg::Vec2Array> vt = new osg::Vec2Array(); //添加纹理坐标 vt->push_back(osg::Vec2( 0, 0)); vt->push_back(osg::Vec2( 1, 0)); vt->push_back(osg::Vec2( 1, 1)); vt->push_back(osg::Vec2( 0, 1)); //设置纹理坐标 geom->setTexCoordArray( 0, vt.get()); //创建颜色数组 osg::ref_ptr<osg::Vec4Array> vc = new osg::Vec4Array(); //添加数据 vc->push_back(osg::Vec4( 1, 0, 0, 1)); vc->push_back(osg::Vec4( 0, 1, 0, 1)); vc->push_back(osg::Vec4( 0, 0, 1, 1)); vc->push_back(osg::Vec4( 1, 1, 0, 1)); //设置颜色数组 geom->setColorArray(vc.get()); //设置颜色的绑定方式为单个顶点 geom->setColorBinding(osg::Geometry::BIND_PER_VERTEX); //创建法线数组 osg::ref_ptr<osg::Vec3Array> nc = new osg::Vec3Array(); //添加法线 nc->push_back(osg::Vec3( 0, - 1, 0)); //设置法线 geom->setNormalArray(nc.get()); //设置法绑定为全部顶点 geom->setNormalBinding(osg::Geometry::BIND_OVERALL); //添加图元 geom->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4)); //添加到叶子节点 geode->addDrawable(geom.get()); osg::StateSet* stateset = new osg::StateSet; osg::Texture2D* texture = new osg::Texture2D(); texture->setDataVariance(osg::Object::DYNAMIC); texture->setImage(osgDB::readImageFile( "/sdcard/osg/texture.jpg")); osg::Uniform* samUniform = new osg::Uniform(osg::Uniform::SAMPLER_2D, "sam"); samUniform->set( 0); //设置纹理单元 stateset->addUniform(samUniform); stateset->setTextureAttributeAndModes( 0, texture, osg::StateAttribute::ON); geode->setStateSet(stateset); return geode.get(); } |
运行结果
3 几点注意:
(1)由于移动平台GPU的强弱,shader中有的支持高精度的变量,有的仅支持中等精度
vertext shader中可以不声明,默认为highp
fragment shader必须声明,opengles 规范没有强制要求fragment shader 必须支持highp,所以如果GPU支持,宏
GL_FRAGMENT_PRECISION_HIGH肯定会被定义,所以可以用下面的语句做为shader的开始
1
2 3 4 5 |
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float; #else precision mediump float; #endif |
(2)由于桌面平台的闲置,shader中有些内置变量不支持(例如gl_TexCoord[x]),OpenGL ES的着色器里规范里面没有这
些变量,它们都是通过用户自定义的着色器来替代的。《OpenGL ES Programming Guide》里面有详细的讲解。嵌入式版本的规
范与计算机版本的规范存在很大的差异性。