6.4.4 GLSL实现奶牛颜色动态变化

该代码示例展示了如何在OpenGL环境中使用OpenSceneGraph(osg)库创建和管理顶点及片段着色器,以及如何通过统一变量回调函数动态更新颜色,实现物体表面颜色的闪烁效果。程序中定义了顶点和片段着色器源码,处理光照和法线,同时定义了一个颜色回调类,每帧更新着色器中的颜色值,导致物体颜色在预设阈值间变化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include <osg/Program>
#include <osgDB/ReadFile>
#include <osgViewer/Viewer>

static const char* vertSource = {
    "varying vec3 normal;\n"//易变量 用于着色器之间的传值
    "void main()\n"
    "{\n"
    "    normal = normalize(gl_NormalMatrix * gl_Normal);\n" //把法线向量从物体空间转化到视觉空间。
    "    gl_Position = ftransform();\n" //相当于 gl_Position = ModelViewProjectionMatrix * gl_Vertex,
                                                //模型视图投影矩阵与空间顶点位置相乘,得到裁剪空间顶点位置。
    "}\n"
};

static const char* fragSource = {
    "uniform vec4 mainColor;\n"  //外面程序输入的颜色
    "varying vec3 normal;\n"    //上面的顶点着色器传的法线
    "void main()\n"
    "{\n"
    "    float intensity = dot(vec3(gl_LightSource[0].position), normal);\n" //计算光照位置与法线的点积,为什么这么做,知道的朋友不吝赐教下。
                                                                            //按照我的理解就是计算了一下亮度值。
    //给输出的颜色赋值
    "    if (intensity > 0.95) gl_FragColor = mainColor;\n" //如果这个值大于0.95,则输出颜色为mainColor,而uniform回调中每帧在来回改这个值,所
                                                            //以这一部分会出现闪烁的效果。
    "    else if (intensity > 0.5) gl_FragColor = vec4(0.6,0.3,0.3,1.0);\n"
    "    else if (intensity > 0.25) gl_FragColor = vec4(0.4,0.2,0.2,1.0);\n"
    "    else gl_FragColor = vec4(0.2,0.1,0.1,1.0);\n"
    "}\n"
};


/* 一直变量uniform回调类,主要用于每帧更新着色器中的用户数据,从而改变渲染的行为和输出结果。     */


class ColorCallback : public osg::Uniform::Callback
{
public:
    ColorCallback() : _incRed(false) {}

    virtual void operator()(osg::Uniform* uniform, osg::NodeVisitor* nv)
    {
        if (!uniform) return;

        osg::Vec4 color;
        uniform->get(color);//获取通过uniform 设置进去的值mainColor

        if (_incRed == true)//3、如果r减到0呢,就给他一直加。
        {
            if (color.x() < 1.0) color.x() += 0.1;
            else _incRed = false;//4、如果加到1就给他再减。
        }
        else
        {
            if (color.x() > 0.0) color.x() -= 0.1;//1、如果RGB中的r分量大于0,则一直减小。
            else _incRed = true;// 2、r减到0了。
        }
        uniform->set(color);
    }

protected:
    bool _incRed;
};

void createShaders(osg::StateSet& ss)
{
    osg::ref_ptr<osg::Shader> vertShader = new osg::Shader(osg::Shader::VERTEX, vertSource);
    osg::ref_ptr<osg::Shader> fragShader = new osg::Shader(osg::Shader::FRAGMENT, fragSource);

    osg::ref_ptr<osg::Program> program = new osg::Program;
    program->addShader(vertShader.get());
    program->addShader(fragShader.get());

    osg::ref_ptr<osg::Uniform> mainColor = new osg::Uniform("mainColor", osg::Vec4(0.5, 0.5, 0.5, 1.0));//这个部分的颜色是闪烁部分的颜色值。
    mainColor->setUpdateCallback(new ColorCallback);

    ss.addUniform(mainColor.get());
    ss.setAttributeAndModes(program.get());
}

int main(int argc, char** argv)
{
    osg::ArgumentParser arguments(&argc, argv);
    osg::Node* model = osgDB::readNodeFiles(arguments);
    if (!model) model = osgDB::readNodeFile("cow.osg");

    createShaders(*(model->getOrCreateStateSet()));

    osgViewer::Viewer viewer;
    viewer.setSceneData(model);
    viewer.setUpViewInWindow(20, 20, 600, 600);
    return viewer.run();
}

效果如下:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值