上篇的代码仅仅是将图形显示,并通过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
C++ Code
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
C++ Code
1
2
3
4
5
static const char gFragmentShader[] =
“varying mediump vec4 col; \n”
“void main() { \n”
” gl_FragColor = col; \n”
“} \n”;
修改createNode()
C++ Code
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<:node> OsgMainApp::createNode() {
//创建一个叶节点对象 osg::ref_ptr<:geode> geode = new osg::Geode();
//创建一个几何体对象 osg::ref_ptr<:geometry> geom = new osg::Geometry();
//添加顶点数据 注意顶点的添加顺序是逆时针 osg::ref_ptr<: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<: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<: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<: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
C++ Code
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代码
C++ Code
1
2
3
4
5
6
static const char gFragmentShader[] =
“varying mediump vec4 col; \n”
“void main() { \n”
” gl_FragColor = col; \n”
“} \n”;
修改createNode()
C++ Code
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<:node> OsgMainApp::createNode() {
//创建一个叶节点对象 osg::ref_ptr<:geode> geode = new osg::Geode();
//创建一个几何体对象 osg::ref_ptr<:geometry> geom = new osg::Geometry();
//添加顶点数据 注意顶点的添加顺序是逆时针 osg::ref_ptr<: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<: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<: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<: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将颜色的地址传入
C++ Code
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
C++ Code
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
C++ Code
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()
C++ Code
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<:node> OsgMainApp::createNode() {
//创建一个叶节点对象 osg::ref_ptr<:geode> geode = new osg::Geode();
//创建一个几何体对象 osg::ref_ptr<:geometry> geom = new osg::Geometry();
//添加顶点数据 注意顶点的添加顺序是逆时针 osg::ref_ptr<: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<: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<: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<: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的开始
C++ Code
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》里面有详细的讲解。嵌入式版本的规
范与计算机版本的规范存在很大的差异性。