查看: 2076|回复: 18

新手跪求指错:再问着色器~

[复制链接]

该用户从未签到

发表于 2012-9-26 16:45:04 | 显示全部楼层 |阅读模式
    最近反复写一个着色器,目的是指定圆内的模型局部着红色,区域外的那部分着绿色。。。现在我已经写好着色器,包括模型顶点的遍历,但始终实现不了效果,希望各位高手进来指点下毛病
   PS:新手较笨,老问着色,希望见谅~

代码:
   static const char* vertSource = {     //顶点着色器
        "varying float ColorPX;\n"
        "varying float ColorPY;\n"
        "varying float dis;    \n"

        "uniform vec3 VertexP; \n"
        "uniform float X;\n"
        "uniform float Y;\n"
       
        "void main()\n"
        "{\n"
        "    ColorPX=VertexP.x;\n"
        "    ColorPY=VertexP.y;\n"
        "    dis=sqrt( (ColorPX-X)*(ColorPX-X) + (ColorPY-Y)*(ColorPY-Y) );\n"   //顶点到圆心的距离
        "    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
        "}\n"
};

static const char* fragSource = {                                         //片元着色器
        "uniform vec3 BrickColor,MortarColor;\n"
        "uniform float R;\n"                         //半径

        "varying float dis; \n"

        "void main()\n"
        "{\n"
        "    vec3 color;                                                     \n"
        "    float useBrick;                                                 \n"
        "    useBrick=step(R,dis);                                       \n"    //step()方法比较‘顶点到圆心的距离’与圆区域的半径
        "    color=mix(MortarColor,BrickColor,useBrick);       \n"   //在圆内(<R)和不在圆内(>R)
        "    gl_FragColor=vec4(color,1.0);                            \n"
        "}\n"
};

void createShaders( osg::ref_ptr <osg::Node> node)
{       
        osg::StateSet *ss=node->getOrCreateStateSet();

        osg::ref_ptr<osg:rogram> program = new osg::Program;

        osg::ref_ptr<osg::Shader> vertShader = new osg::Shader( osg::Shader::VERTEX, vertSource );  //顶点着色器
        program->addShader( vertShader.get() );

        osg::ref_ptr<osg::Shader> fragShader = new osg::Shader( osg::Shader::FRAGMENT, fragSource );//片元着色器
        program->addShader( fragShader.get() );


        osg::ref_ptr<osg::Uniform> R = new osg::Uniform( "R", r );   //圆的半径
        ss->addUniform( R.get() );

        osg::ref_ptr<osg::Uniform> X = new osg::Uniform( "X", x );  //圆心x
        ss->addUniform( X.get() );

        osg::ref_ptr<osg::Uniform> Y = new osg::Uniform( "Y", y );  //圆心y
        ss->addUniform( Y.get() );       


        VertexExtractor iv;   //顶点遍历
        node->accept(iv);
        int size_t=iv.extracted_verts.get()->size();
    std::vector <osg::Vec3> ::iterator iter=iv.extracted_verts.get()->begin();

        for (int i=0;i<size_t;i++)
        {
                std::cout<<iter->x()<<" "<<iter->y()<<std::endl; //顶点的x、y值输出
                osg::Vec3 pP((iter->x()),(iter->y()),0);  //自定义一个点
                iter++;

                osg::ref_ptr<osg::Uniform> VertexP = new osg::Uniform( "VertexP", pP); //设断点调试不为空
                ss->addUniform( VertexP.get() );

                osg::ref_ptr<osg::Uniform> BrickColor = new osg::Uniform( "BrickColor", osg::Vec3(1.0,0.0,0.0) );
                ss->addUniform( BrickColor.get() );

                osg::ref_ptr<osg::Uniform> MortarColor = new osg::Uniform( "MortarColor", osg::Vec3(0.0,0.8,0.0) );
                ss->addUniform( MortarColor.get() );
             }

        ss->setAttributeAndModes( program.get() );
}

问题:
zhuo.bmp

该用户从未签到

发表于 2012-9-26 17:04:45 | 显示全部楼层
1. 可以把useBrick打印出来,看看它的结果是不是要么为1, 要么为0
2. 可能是因为在外面的vertex的颜色是绿色,而你opengl设置的shadermode为GL_FLAT, 所以导致这个问题。

我也是osg新手。

该用户从未签到

 楼主| 发表于 2012-9-27 09:04:54 | 显示全部楼层
zengqh 发表于 2012-9-26 17:04
1. 可以把useBrick打印出来,看看它的结果是不是要么为1, 要么为0
2. 可能是因为在外面的vertex的颜色是绿 ...

你好,我也想到了Opengl中的单调着色,和平滑着色。在代码中我写入过“ss->setMode(GL_SMOOTH,osg::StateAttribute::ON);”告诉着色器对每个顶点进行独立的操作,也就是平滑着色模型那样。。。可是会报错。。哎,真不知道怎么弄了,新手不好过啊这年头儿~

zhuo2.bmp

zhuo.bmp

该用户从未签到

发表于 2012-9-27 09:58:14 | 显示全部楼层
  1. for (int i=0;i<size_t;i++)
  2.         {
  3.                 std::cout<<iter->x()<<" "<<iter->y()<<std::endl; //顶点的x、y值输出
  4.                 osg::Vec3 pP((iter->x()),(iter->y()),0);  //自定义一个点
  5.                 iter++;

  6.                 osg::ref_ptr<osg::Uniform> VertexP = new osg::Uniform( "VertexP", pP); //设断点调试不为空
  7.                 ss->addUniform( VertexP.get() );
复制代码
其他地方我没有看,这里我想您的一个误区是:Uniform是对于所有计算单元一致的,因此您设置的VertexP只有最后一个是有效的,并且它会应用于所有参与计算的Vertex。如果您需要给每个顶点设置一个自定义变量,请使用attribute
至于GL_SMOOTH,这个是默认的,要改变默认值可以通过ShadeModel状态来完成

该用户从未签到

发表于 2012-9-27 10:03:22 | 显示全部楼层
mxl12315 发表于 2012-9-27 09:04
你好,我也想到了Opengl中的单调着色,和平滑着色。在代码中我写入过“ss->setMode(GL_SMOOTH,osg::State ...

ss->setMode(GL_SMOOTH,osg::StateAttribute::ON);
在opengl当中,这个API已经废弃了(glShaderModel).

需要在变量前加上smooth关键字,具体你google下。(glsl smooth)

你把useBrick打印出来了么(把useBrick作为输出颜色),因为你这个绿色模型的点相对比较小,如果整个模型一起画的时候,会导致使用最外面顶点的
颜色。

第二点,你可以把绿色模型放到圆内部,看一下颜色对不对,如果对,那肯定就是flat与gouraud着色的问题。

该用户从未签到

发表于 2012-9-27 10:08:50 | 显示全部楼层
array 发表于 2012-9-27 09:58
其他地方我没有看,这里我想您的一个误区是:Uniform是对于所有计算单元一致的,因此您设置的VertexP只有最 ...

array兄说得有道理。很久不写glsl了,有点生疏了. GL_SMOOTH确实是默认的。

该用户从未签到

 楼主| 发表于 2012-9-27 10:10:44 | 显示全部楼层
array 发表于 2012-9-27 09:58
其他地方我没有看,这里我想您的一个误区是:Uniform是对于所有计算单元一致的,因此您设置的VertexP只有最 ...

现在我简化了代码,确实如您所说,是我自己定义的那个顶点变量问题,我看到GLSL着色语言那本书中只写过生明一个顶点属性,比如您说的用attribute gl_Vertex; 书中提及设置顶点属性的标准属性部分(比如顶点位置)可由用户随意设置其值并靠opengl存储它们。。。我想问您下,针对我自己设的VertexP,如何关联?
   比如类似顶点着色器中自定义一个uniform一致变量,那么可在createshader()中写入<osg::uniform>.....和->adduniform()

   还望您指点下,麻烦了~

该用户从未签到

发表于 2012-9-27 10:16:45 | 显示全部楼层
attribute的设置比uniform要复杂一点,第一是对于Geometry设置setVertexAttribArray(),注意index不能随便设置,OpenGL对于其中大部分已经有了定义,一般来说6,7是用户自己可用的
第二是设置Program的方法,addBindAttribLocation(),然后在shader中声明这个attribute即可

该用户从未签到

发表于 2012-9-27 10:20:33 | 显示全部楼层
直接用gl_Vertex不可以么?

该用户从未签到

 楼主| 发表于 2012-9-27 10:28:45 | 显示全部楼层
array 发表于 2012-9-27 10:16
attribute的设置比uniform要复杂一点,第一是对于Geometry设置setVertexAttribArray(),注意index不能随便设 ...

好,我去试试~这个没接触过,新鲜哈!

该用户从未签到

发表于 2012-9-27 10:31:58 | 显示全部楼层
mxl12315 发表于 2012-9-27 10:27
啊,您原来写过着色器?太好了,我也开始觉得着色器始终只处理了遍历出的最后一个顶点,其他顶点没用过。 ...

array兄说过了。。。

该用户从未签到

 楼主| 发表于 2012-9-27 10:43:32 | 显示全部楼层
array 发表于 2012-9-27 10:16
attribute的设置比uniform要复杂一点,第一是对于Geometry设置setVertexAttribArray(),注意index不能随便设 ...

其实,我还是有个遗留问题想请教您,我觉得如果直接调用模型本身的gl_Vertex.x和gl_Vertex.y,然后求它们到圆心的距离,最后与半径比较,大于小于分别设色,您看这样为什么不行?我之前发过一个帖子,您今天也回复了让我进行堆栈调试。。这个思路可行吗?

该用户从未签到

发表于 2012-9-27 10:47:40 | 显示全部楼层
mxl12315 发表于 2012-9-27 10:43
其实,我还是有个遗留问题想请教您,我觉得如果直接调用模型本身的gl_Vertex.x和gl_Vertex.y,然后求它们 ...

这个当然不行。因为gl_Vertex存储的是模型的局部坐标,需要乘以世界矩阵后再比较。

我的意思是指是不是不用另外加一个attribute, 而用gl_Vertex, 只是得乘以世界矩阵后再比较而已。

该用户从未签到

 楼主| 发表于 2012-9-27 11:06:50 | 显示全部楼层
zengqh 发表于 2012-9-27 10:47
这个当然不行。因为gl_Vertex存储的是模型的局部坐标,需要乘以世界矩阵后再比较。

我的意思是指是不是 ...

那我也试试这个~完后告诉您~

该用户从未签到

发表于 2012-9-27 11:07:39 | 显示全部楼层
我也在学习OSG。貌似现在有些虚拟现实用这个引擎。
一起学习吧。。。

该用户从未签到

 楼主| 发表于 2012-9-27 11:24:15 | 显示全部楼层
zengqh 发表于 2012-9-27 10:47
这个当然不行。因为gl_Vertex存储的是模型的局部坐标,需要乘以世界矩阵后再比较。

我的意思是指是不是 ...

嘿嘿~我比您还新手呢,刚接触OSG两个月。。。您说的世界矩阵是gl打头的吧?我是直接上手学osg,没看opengl。。弱弱问您下,世界矩阵怎么写?见笑 了

该用户从未签到

发表于 2012-9-27 11:38:52 | 显示全部楼层
ogl2.0当中没有世界矩阵这个变量。
有两个方法:
1. 手动把世界矩阵通过uniform设置进来
2. 取得摄像头的矩阵,假设为v, v(-1)为v的逆矩阵,gl_ModelViewMatirx为模型视图矩阵。
那么model matrix = v(-1) * gl_ModelViewMatirx;

找个时间我也来写个demo,就你那个也行。细节很重要的。光说不练,眼高手低是不行的。

该用户从未签到

发表于 2012-9-27 18:02:47 | 显示全部楼层
zengqh 发表于 2012-9-27 11:38
ogl2.0当中没有世界矩阵这个变量。
有两个方法:
1. 手动把世界矩阵通过uniform设置进来

我也超新手,来问您一下有关世界矩阵的问题哈~
         (1) 首先,你说的手动设置摄像头的矩阵是指Camera.setViewMatrixas()这句吗?
      (2)其次,你举例的逆矩阵这里我没明白,比如我写一个方法体,能否return “摄像头矩阵”?再者,如果可以通过方法返回值得出,如何写它的逆呢?
      
   PS:我大菜鸟,帖子勿删,谢谢了

该用户从未签到

 楼主| 发表于 2012-9-27 18:49:59 | 显示全部楼层
zengqh 发表于 2012-9-27 11:38
ogl2.0当中没有世界矩阵这个变量。
有两个方法:
1. 手动把世界矩阵通过uniform设置进来

我和楼上的方法不同,您看我这样写可以得到您说的那个世界矩阵吗?
  代码:
    osg::Matrixd m=viewer->getCamera()->getViewMatrix();
      osg::Matrixd inverseM=m.inverse(m);


在顶点着色器中:
    gl_Position=inverseM * gl_ModelViewMatirx *gl_Vertex;

   您看这样可以吗?
您需要登录后才可以回帖 登录 | 注册

本版积分规则

OSG中国官方论坛-有您OSG在中国才更好

网站简介:osgChina是国内首个三维相关技术开源社区,旨在为国内更多的技术开发人员提供最前沿的技术资讯,为更多的三维从业者提供一个学习、交流的技术平台。

联系我们

  • 工作时间:09:00--18:00
  • 反馈邮箱:1315785073@qq.com
快速回复 返回顶部 返回列表