第34节 实例-这叫个啥效果呢,颜色分段显示?

网友发来的效果图

在这里插入图片描述
这个鸭头的特别之处在于颜色被分成了一段一段的,而且不是沿顶点来分的。网友自己做的效果如下:
在这里插入图片描述
本节的内容在网盘中:

请使用浏览器打开,平时遇到问题或加群也可以加我微信: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();
}

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片