网友发来的效果图
这个鸭头的特别之处在于颜色被分成了一段一段的,而且不是沿顶点来分的。网友自己做的效果如下:
本节的内容在网盘中:
请使用浏览器打开,平时遇到问题或加群也可以加我微信:13324598743:
【击此打开网盘资源链接】
关键点
其实这个效果非常简单,只需要在顶点着色器中把颜色按顶点计算好,然后在片元着色器中进行规范:
我的顶点着色器计算颜色值的地方,就是直接把顶点值乘个0.7就赋给颜色值了,因为我画的是一个球,这个球的半径是1,因此不会超出颜色的范围:
vec3 ambient = vec3(0.7, 0.7, 0.7) * VertexPosition;
vLightIntensity = ambient;
顶点着色器输出了vLightIntensity ,在片元着色器中拿到了自动插值后的vLightIntensity ,【理解的关键点来了】也就是每个片元都有了vLightIntensity ,不再是只是顶点有值,三个顶点围成的三角形里面每个要着色的像素都有了 vLightIntensity ,这是顶点着色器到片元着色器之间自动完成的。
然后在片元着色器进行分段,这里rgb分段的方式相同,也就是小于0.2就认为是0.5, 小于0.5就认为是0.7,其它情况一概0.2这样整个物体就只有这三种r,对gb也施以此法,则整个球的颜色就是一片一片的,像尿布似的:
if(r<0.2) r_out = 0.5;
else if(r<0.5) r_out = 0.7;
else r_out = 0.2;
if(g<0.2) g_out = 0.5;
else if(g<0.7) g_out = 0.7;
else g_out = 0.2;
if(b<0.2) b_out = 0.5;
else if(b<0.5) b_out = 0.7;
else b_out = 0.2;
如下图:
其它
关于球的绘制,因为我是用的我其它工程的代码,有点复杂,可以不细看。这里讲一下网格与球的关系,它们是分开绘制的,因为顶点都相同,因此会闪烁。这里可以用PolygonOffset给球体指定一个微小的偏移,使球远离视点一丢丢,则就不会闪烁了。
new osg::PolygonOffset(1.0, 1.0);
是远离视点
new osg::PolygonOffset(-1.0, -1.0);
是靠近视点。这两个值具体所起的作用可以百度一下。比较复杂。
本节代码注意有shader
basic.vert
#version 410
layout (location=0) in vec3 VertexPosition;
layout (location=1) in vec3 VertexNormal;
layout (location=1) out vec3 vLightIntensity;
uniform mat3 osg_NormalMatrix;
uniform mat4 osg_ModelViewMatrix;
uniform mat4 osg_ModelViewProjectionMatrix;
void main()
{
vec3 n = normalize( osg_NormalMatrix * VertexNormal);
vec4 camCoords = osg_ModelViewMatrix * vec4(VertexPosition,1.0);
vec3 ambient = vec3(0.7, 0.7, 0.7) * VertexPosition;
vLightIntensity = ambient;
gl_Position = osg_ModelViewProjectionMatrix * vec4(VertexPosition,1.0);
}
basic.frag
#version 410
layout(location=0) out vec4 FragColor;
layout (location=1) in vec3 vLightIntensity;
void main() {
//对其规范化形成条带
//先处理r
//r小于0.5都置1.0
float r, g, b;
r = vLightIntensity.x;
g = vLightIntensity.y;
b = vLightIntensity.z;
float r_out, g_out, b_out;
if(r<0.2) r_out = 0.5;
else if(r<0.5) r_out = 0.7;
else r_out = 0.2;
if(g<0.2) g_out = 0.5;
else if(g<0.7) g_out = 0.7;
else g_out = 0.2;
if(b<0.2) b_out = 0.5;
else if(b<0.5) b_out = 0.7;
else b_out = 0.2;
FragColor = vec4(r_out, g_out, b_out, 1.0);
}
main.cpp
#include <osgViewer/Viewer>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/PrimitiveSet>
#include <osgGA/GUIEventHandler>
#include <osgGA/CameraManipulator>
#include <osgDB/ReadFile>
#include <osg/Geode>
#include <osg/ShapeDrawable>
#include <osg/Geometry>
#include <osgUtil/SmoothingVisitor>
#include <osg/PolygonOffset>
#include <osgGA/StateSetManipulator>
osg::Group* _root = new osg::Group;
osg::Node* CreateSphere()
{
//半径设置成1.0,这样顶点值就可以直接设置成颜色值
float _r = 1.0;
osg::Geode* _gnode = new osg::Geode;
//_gnode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED);
//球体
osg::Geometry* geom = new osg::Geometry;
_gnode->addDrawable(geom);
osg::PolygonOffset* po = new osg::PolygonOffset(1.0, 1.0);
geom->getOrCreateStateSet()->setAttributeAndModes(po, osg::StateAttribute::ON|osg::StateAttribute::PROTECTED);
osg::StateSet* ss = geom->getOrCreateStateSet();
osg::Program* prom = new osg::Program;
ss->setAttributeAndModes(prom, osg::StateAttribute::ON);
prom->addShader(osgDB::readRefShaderFile("shader/basic.vert"));
prom->addShader(osgDB::readRefShaderFile("shader/basic.frag"));
//勾边
osg::Geometry* geomLine = new osg::Geometry;
_gnode->addDrawable(geomLine);
geomLine->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED);
osg::Vec3Array* _vertex = new osg::Vec3Array();
geom->setVertexArray(_vertex);
geomLine->setVertexArray(_vertex);
//设置线的颜色
osg::Vec4Array* lineColor = new osg::Vec4Array();
lineColor->push_back(osg::Vec4(0.0, 0.0, 0.0, 1.0));
geomLine->setColorArray(lineColor, osg::Array::BIND_OVERALL);
//使用三角形绘制
osg::DrawElementsUInt* up = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES, 0);
geom->addPrimitiveSet(up);
osg::DrawElementsUInt* upLine = new osg::DrawElementsUInt(osg::PrimitiveSet::LINE_LOOP, 0);
geomLine->addPrimitiveSet(upLine);
float delta_degree = 15.0;
int delta_theta_i = 1 + (360.0 - 0.001) / delta_degree;
int delta_phi_i = 1 + (180.0 + 0.001) / delta_degree;
int thetaIndex = 0;
int phiIndex = 0;
for (float theta = 0.0; theta < (360.0 - 0.001); theta += delta_degree, thetaIndex++)
{
//一列的顶点个数
float cos_theta = std::cos(osg::inDegrees(theta));
float sin_theta = std::sin(osg::inDegrees(theta));
phiIndex = 0;
for (float phi = -90.0; phi < (90 + 0.001); phi += delta_degree, phiIndex++)
{
//最后一列要连上第一列
if (thetaIndex < (delta_theta_i - 1))
{
//第0个压入一个三角形
if (0 == phiIndex)
{
up->push_back(thetaIndex * delta_phi_i + phiIndex + 1);
up->push_back((thetaIndex + 1) * delta_phi_i + phiIndex);
up->push_back(thetaIndex * delta_phi_i + phiIndex);
}
else if (phiIndex < (delta_phi_i - 1))//中间的压两个三角形
{
up->push_back(thetaIndex * delta_phi_i + phiIndex + 1);
up->push_back((thetaIndex + 1) * delta_phi_i + phiIndex);
up->push_back(thetaIndex * delta_phi_i + phiIndex);
up->push_back((thetaIndex + 1) * delta_phi_i + phiIndex);
up->push_back((thetaIndex + 1) * delta_phi_i + phiIndex - 1);
up->push_back(thetaIndex * delta_phi_i + phiIndex);
}
else //最后一个压入一个三角形
{
up->push_back((thetaIndex + 1) * delta_phi_i + phiIndex);
up->push_back((thetaIndex + 1) * delta_phi_i + phiIndex - 1);
up->push_back(thetaIndex * delta_phi_i + phiIndex);
}
}
else
{
//第0个压入一个三角形
if (0 == phiIndex)
{
up->push_back(phiIndex + 1);
up->push_back(phiIndex);
up->push_back(thetaIndex * delta_phi_i + phiIndex);
}
else if (phiIndex < (delta_phi_i - 1))//中间的压两个三角形
{
up->push_back(thetaIndex * delta_phi_i + phiIndex + 1);
up->push_back(phiIndex);
up->push_back(thetaIndex * delta_phi_i + phiIndex);
up->push_back(phiIndex);
up->push_back(phiIndex - 1);
up->push_back(thetaIndex * delta_phi_i + phiIndex);
}
else //最后一个压入一个三角形
{
up->push_back(phiIndex);
up->push_back(phiIndex - 1);
up->push_back(thetaIndex * delta_phi_i + phiIndex);
}
}
_vertex->push_back((osg::Vec3(_r*cos_theta*std::cos(osg::inDegrees(phi)), _r*std::sin(osg::inDegrees(phi)), _r*sin_theta*std::cos(osg::inDegrees(phi)))));
}
}
//拷贝
for (int i = 0; i < up->size(); i++)
{
upLine->push_back(up->at(i));
}
//重构法线
osgUtil::SmoothingVisitor::smooth(*geom);
return _gnode;
}
int main()
{
osgViewer::Viewer viewer;
_root->addChild(CreateSphere());
viewer.setSceneData(_root);
viewer.getCamera()->setClearColor(osg::Vec4(0.4, 0.4, 0.4, 1.0));
viewer.addEventHandler(new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()));
viewer.realize();
viewer.getCamera()->getGraphicsContext()->getState()->setUseModelViewAndProjectionUniforms(true);
viewer.getCamera()->getGraphicsContext()->getState()->setUseVertexAttributeAliasing(true);
return viewer.run();
}
暂无评论内容