查看: 2070|回复: 15

圆柱体面贴图和漫游问题

[复制链接]

该用户从未签到

发表于 2014-4-17 11:19:51 | 显示全部楼层 |阅读模式
本帖最后由 rubby 于 2014-4-17 11:26 编辑

各位好:

本人是osg新手,刚学一个月,刚刚拜读完各位版主的大作。我们领导就开始催东西了。

遇到些问题,描述如下,如能给予些指导,不胜感激:

目标:
我想对圆柱体表面进行贴图,包含内外两个表面。
这两个表面的贴图是一样的,可以从外面看,也可以从圆柱体内部看。

我想从圆柱体顶到圆柱体底进行漫游,周围的贴图随深度变化。



问题:
1.1 由于圆柱体中间各部分的直径可以不同,我就采用 圆柱体叠加的方法解决。(圆柱体通过 osg::Cylinder生成)
比如先指定圆柱体1直径为x,圆柱体2直径为y,然后平移他们的位置,叠在一起。
1.2 对圆柱体1 和圆柱体2 进行贴图。
    现在是直接从文件读入image对象,后期需要根据数据写像素点来生成Image。
   问题(1): 但是这种方法贴图,只能贴在圆柱体外表面,而我需要的是圆柱体内外两面,如何实现内表面的贴图?
   问题(2): 如何将osg::Cylinder设定为空心,使之无顶端和底端  ?
  问题(3) :这种贴图方法,会对圆柱体顶端和底端也贴图,如何去除。?

问题(4)从圆柱体顶到圆柱体底进行漫游,周围的贴图随深度变化。
是不是利用路径漫游? 由于实际项目中圆柱体可能非常长,比如几千米,我认为不能一次将场景图创建好(这样占用内存太大),
而是根据当前所处位置,动态变化周围场景。是否需要使用分页数据库技术?

代码如下,现在的效果见附件的截图。

谢谢你们的时间和回复。thanks .



  1. float radius = 1.f;
  2.         float height = 5.f;
  3.         osg::TessellationHints* hints = new osg::TessellationHints;
  4.         hints->setDetailRatio(0.5f);


  5.         osg::ref_ptr<osg::Group> group = new osg::Group;
  6.         osg::ref_ptr<osg::Geode> genode = new osg::Geode;

  7.         osg::ref_ptr<osg::Geode> genode2 = new osg::Geode;

  8.         osg::ref_ptr<osg::ShapeDrawable> drawable = new osg::ShapeDrawable(new osg::Cylinder(osg::Vec3(0.0f,0.0f,0.0f),radius,height),hints);
  9.         osg::ref_ptr<osg::ShapeDrawable> drawable2 = new osg::ShapeDrawable(new osg::Cylinder(osg::Vec3(0.0f,0.0f,0.0f),radius+1,height),hints);
  10.         genode->addDrawable(drawable);//TODO geom.get() or gemo. both are ok.
  11.         genode2->addDrawable(drawable2);//TODO geom.get() or gemo. both are ok.


  12.         osg::ref_ptr<osg::MatrixTransform> tans = new osg::MatrixTransform;
  13.         tans->setMatrix(osg::Matrix::translate(0,0,2.5f));
  14.         tans->addChild(genode.get());

  15.         osg::ref_ptr<osg::MatrixTransform> tans2 = new osg::MatrixTransform;
  16.         tans2->setMatrix(osg::Matrix::translate(0,0,-2.5f));
  17.         tans2->addChild(genode2.get());

  18.         group->addChild(tans2);
  19.         group->addChild(tans);

  20.         //1, 设置状态和贴图 (第一个节点)
  21.         {
  22.                 osg::StateSet* state = genode->getOrCreateStateSet();
  23.                 state->setMode( GL_LIGHTING, osg::StateAttribute::OFF |
  24.                         osg::StateAttribute::PROTECTED );
  25.                 state->setRenderingHint( osg::StateSet::TRANSPARENT_BIN );       

  26.                 // Load the texture image
  27.                 std::string fileName( "Picea_pungens__blue_spruce15_256.png" );
  28.                 osg::ref_ptr<osg::Image> image = osgDB::readImageFile( fileName );
  29.                 if (!image.valid())
  30.                 {
  31.                         osg::notify( osg::FATAL ) << "Unable to load data file. Exiting." << std::endl;
  32.                         return( NULL );
  33.                 }

  34.                 // Set the image in a Texture2D object
  35.                 osg::ref_ptr<osg::Texture2D> tex = new osg::Texture2D;
  36.                 tex->setImage( image.get() );
  37.                 // After creating the OpenGL texture object, release the
  38.                 //   internal ref_ptr<Image> (to delete the Image).
  39.                 tex->setUnRefImageDataAfterApply( true );
  40.                 state->setTextureAttributeAndModes( 0, tex.get() );
  41.         }
  42.         //2, 设置状态和贴图 (第2个节点)
  43.         {
  44.                 osg::StateSet* state = genode2->getOrCreateStateSet();
  45.                 state->setMode( GL_LIGHTING, osg::StateAttribute::OFF |
  46.                         osg::StateAttribute::PROTECTED );
  47.                 state->setRenderingHint( osg::StateSet::TRANSPARENT_BIN );       

  48.                 // Load the texture image
  49.                 std::string fileName( "forestRoof.png" );
  50.                 osg::ref_ptr<osg::Image> image = osgDB::readImageFile( fileName );
  51.                 if (!image.valid())
  52.                 {
  53.                         osg::notify( osg::FATAL ) << "Unable to load data file. Exiting." << std::endl;
  54.                         return( NULL );
  55.                 }

  56.                 // Set the image in a Texture2D object
  57.                 osg::ref_ptr<osg::Texture2D> tex = new osg::Texture2D;
  58.                 tex->setImage( image.get() );
  59.                 // After creating the OpenGL texture object, release the
  60.                 //   internal ref_ptr<Image> (to delete the Image).
  61.                 tex->setUnRefImageDataAfterApply( true );
  62.                 state->setTextureAttributeAndModes( 0, tex.get() );

  63.         }
  64.         return group.get();
复制代码



     





截图.png

该用户从未签到

 楼主| 发表于 2014-4-22 13:38:18 | 显示全部楼层
问题(3) :这种贴图方法,会对圆柱体顶端和底端也贴图,如何去除。?
这个问题解决如下,将setCreateBottom和setCreateTop 设置为空,即可。
多谢buaahc 和ysm两位的指教。
如果遇到相同的问题初学者,可以如下解决。

  1.         osg::TessellationHints* hints = new osg::TessellationHints;
  2.         hints->setDetailRatio(0.5f);
  3.         hints->setCreateBody(true);
  4.         hints->setCreateBottom(false);
  5.         hints->setCreateTop(false);
复制代码

该用户从未签到

 楼主| 发表于 2014-4-18 10:12:55 | 显示全部楼层
没有人理我,是问题太简单吗?。。。

该用户从未签到

发表于 2014-4-18 14:58:01 | 显示全部楼层
使用geometry自己写 圆柱体的各个面,然后贴图。
周围的贴图随深度变化?你是指亮度变化么?亮度的话可以使用灯光衰减。
圆柱从底到顶进行漫游,只要控制相机沿着圆柱进行移动即可,路径漫游可以,但是路径漫游也是需要插入相机的路径点,直接在getinversematrix()岂不是一样。
太长可以使用lod技术,或者动态加载/卸载

该用户从未签到

 楼主| 发表于 2014-4-18 23:25:03 | 显示全部楼层
多谢 buaahc。再麻烦您一下:
1.圆柱体的面是类似矩形卷起来。osg中可以创建线段,三角形,多边形。
并没有发现创建曲面的方法。
2,周围的贴图随深度变化: 我的意思是由于圆柱体很长。每次只显示部分如第0米到100米,用户修改深度为500,此时才显示第500-600。不同深度,纹理不一样。
3.圆柱从底到顶进行漫游,只要控制相机沿着圆柱进行移动即可。 我试一试。应该是利用节点更新和回调方法吧,设置camera.setUpdateCallback(). 然后在operator()方法中控制相机的移动。

但是,我这个相机是需要放在圆柱体内部,看圆柱体内部四周。 也可以放在圆柱体外部,看圆柱体外部。
圆柱体外部贴图 和内部贴图 怎么控制(即纹理如何控制)。我目前通过书中例子只知道:一般设置一个面。不知道如何设置内部贴图。
因为stateSet->setTextureAttributeAndModes(0,tex2D) 并没有方法指定是贴哪面?

4. 太长的问题是:比如3000米的圆柱面,如果我一次性创建它表面的纹理对应的Image,内存应该是不够。圆柱从底到顶进行漫游时,是在控制相机沿着圆柱进行移动时候,同时创建100米的image作为四周圆柱体的纹理吗?感觉这样效率很慢。

多谢您的指教。

该用户从未签到

 楼主| 发表于 2014-4-18 23:25:23 | 显示全部楼层
buaahc 发表于 2014-4-18 14:58
使用geometry自己写 圆柱体的各个面,然后贴图。
周围的贴图随深度变化?你是指亮度变化么?亮度的话可以 ...


多谢 buaahc。再麻烦您一下:
1.圆柱体的面是类似矩形卷起来。osg中可以创建线段,三角形,多边形。
并没有发现创建曲面的方法。
2,周围的贴图随深度变化: 我的意思是由于圆柱体很长。每次只显示部分如第0米到100米,用户修改深度为500,此时才显示第500-600。不同深度,纹理不一样。
3.圆柱从底到顶进行漫游,只要控制相机沿着圆柱进行移动即可。 我试一试。应该是利用节点更新和回调方法吧,设置camera.setUpdateCallback(). 然后在operator()方法中控制相机的移动。

但是,我这个相机是需要放在圆柱体内部,看圆柱体内部四周。 也可以放在圆柱体外部,看圆柱体外部。
圆柱体外部贴图 和内部贴图 怎么控制(即纹理如何控制)。我目前通过书中例子只知道:一般设置一个面。不知道如何设置内部贴图。
因为stateSet->setTextureAttributeAndModes(0,tex2D) 并没有方法指定是贴哪面?

4. 太长的问题是:比如3000米的圆柱面,如果我一次性创建它表面的纹理对应的Image,内存应该是不够。圆柱从底到顶进行漫游时,是在控制相机沿着圆柱进行移动时候,同时创建100米的image作为四周圆柱体的纹理吗?感觉这样效率很慢。

多谢您的指教。

该用户从未签到

发表于 2014-4-19 13:41:53 | 显示全部楼层
1、曲面当然需要自己插点啊。。。哪有那么多现成的,插值点完成后使用GL_Triangle_FAN生成圆柱。
2、动态改变文理不就行了,到500-600米时,换纹理
3、可以使用setUpdateCallback(),但是这样也是改变视图矩阵,我还是建议在漫游器里面直接进行改变,无论使用何种改变最终都要反映在getinverseMatrix()里面,
纹理贴图:如果你是二维面片的话,你在正面贴图,反面也能看见。。。当然看到的方向是反的。。。GL_Triangle_FAN生成的就是三角面片,你插值完成,并贴图这个问题自动就会解决!
使用osg::Cylinder生成的是体,肯定内部看到不到。。。
4、3000米没有必要全部一次显示,看不到的地方有必要精细显示?使用lod技术即可,或者相机移动到哪一块显示那一块就可

该用户从未签到

 楼主| 发表于 2014-4-19 20:58:18 | 显示全部楼层
buaahc 发表于 2014-4-19 13:41
1、曲面当然需要自己插点啊。。。哪有那么多现成的,插值点完成后使用GL_Triangle_FAN生成圆柱。
2、动态 ...

再次感谢您。

请原谅我的愚昧,我大致明白了你的意思。


在国内出版的几本osg书中,还没有看到示例如何插值求点。
我去看看osg官方例子中有没有。
另外,鉴于我没有opengl方面的知识,我查查opengl红宝书和蓝宝书是否有类似的插值例子。

我先尝试下,非常感谢您的时间和回复。

该用户从未签到

发表于 2014-4-20 22:58:15 | 显示全部楼层
与opengl没有关系,怎么插值,自己想吧
更正一个错误:不是GL_Triangle_FAN,是TRIANGLE_STRIP

该用户从未签到

发表于 2014-4-21 10:17:56 | 显示全部楼层
rubby 发表于 2014-4-19 20:58
再次感谢您。

请原谅我的愚昧,我大致明白了你的意思。

osg::Cylinder源码中有插值的算法,一个集合体使用正反两面贴图不行,你使用源码中的算法,自己制作圆柱体,把顶点坐标正方向化一个圆柱体,反方向绘制一个圆柱体,使用同样的纹理图和坐标,能实现两面贴图

该用户从未签到

 楼主| 发表于 2014-4-21 11:11:47 | 显示全部楼层
ysw 发表于 2014-4-21 10:17
osg::Cylinder源码中有插值的算法,一个集合体使用正反两面贴图不行,你使用源码中的算法,自己制作圆柱 ...

多谢ysw。
我想给圆柱体表面进行贴图(纹理):在圆柱体外可以看到,在圆柱体内部也可以看到。

1. 如果仅仅指定圆柱体外部纹理,是不是在内部就看不到?

所以必须创建两个在相同的位置,正反创建两个圆柱体。然后实现两面贴图?

我也会去看osg::Cylinder源码,多谢你的建议。thanks

该用户从未签到

 楼主| 发表于 2014-4-21 11:14:14 | 显示全部楼层
buaahc 发表于 2014-4-20 22:58
与opengl没有关系,怎么插值,自己想吧
更正一个错误:不是GL_Triangle_FAN,是TRIANGLE_STRIP

再次感谢你的回复。

利用TRIANGLE_STRIP, 其思想是否是:多个连接起来的三角形共同构成一个曲面。
如果放大,实际上还是一个个三角形“平面”而非“曲面”


类似于:"曲线"实际上放大也是多段相连的"直线"

thanks

该用户从未签到

发表于 2014-4-21 12:29:44 | 显示全部楼层
rubby 发表于 2014-4-21 11:11
多谢ysw。
我想给圆柱体表面进行贴图(纹理):在圆柱体外可以看到,在圆柱体内部也可以看到。

如果没有背面剔除的话,能看到,不过纹理只有一面是正面,另外一面是反面,而且你设置法线的时候,智能使一面看着是明亮的,如果做内部漫游的话,估计不太好。

该用户从未签到

 楼主| 发表于 2014-4-22 10:02:58 | 显示全部楼层
ysw 发表于 2014-4-21 12:29
如果没有背面剔除的话,能看到,不过纹理只有一面是正面,另外一面是反面,而且你设置法线的时候,智能使 ...

好的,多谢您的热心回答,

我尝试先做出个小的原型出来啦。

该用户从未签到

 楼主| 发表于 2014-4-22 10:55:57 | 显示全部楼层
ysw 发表于 2014-4-21 12:29
如果没有背面剔除的话,能看到,不过纹理只有一面是正面,另外一面是反面,而且你设置法线的时候,智能使 ...

多谢,再麻烦你一下:
我在查找Cylinder的源代码,发现Shape中Cylinder的定义如下,并没有有具体实现

  1. class OSG_EXPORT Cylinder : public Shape
  2. {
  3.     public:

  4.         Cylinder():
  5.             _center(0.0f,0.0f,0.0f),
  6.             _radius(1.0f),
  7.             _height(1.0f) {}

  8.         Cylinder(const osg::Vec3& center,float radius,float height):
  9.             _center(center),
  10.             _radius(radius),
  11.             _height(height) {}

  12.         Cylinder(const Cylinder& cylinder,const CopyOp& copyop=CopyOp::SHALLOW_COPY):
  13.             Shape(cylinder,copyop),
  14.             _center(cylinder._center),
  15.             _radius(cylinder._radius),
  16.             _height(cylinder._height),
  17.             _rotation(cylinder._rotation) {}

  18.         META_Shape(osg, Cylinder);

  19.         inline bool valid() const { return _radius>=0.0f; }

  20.         inline void set(const Vec3& center,float radius, float height)
  21.         {
  22.             _center = center;
  23.             _radius = radius;
  24.             _height = height;
  25.         }

  26.         inline void setCenter(const Vec3& center) { _center = center; }
  27.         inline const Vec3& getCenter() const { return _center; }

  28.         inline void setRadius(float radius) { _radius = radius; }
  29.         inline float getRadius() const { return _radius; }

  30.         inline void setHeight(float height) { _height = height; }
  31.         inline float getHeight() const { return _height; }

  32.         inline void setRotation(const Quat& quat) { _rotation = quat; }
  33.         inline const Quat& getRotation() const { return _rotation; }
  34.         inline Matrix computeRotationMatrix() const { return Matrix(_rotation); }
  35.         bool zeroRotation() const { return _rotation.zeroRotation(); }

  36.     protected:
  37.    
  38.         virtual ~Cylinder();

  39.         Vec3    _center;
  40.         float   _radius;
  41.         float   _height;
  42.         Quat    _rotation;
  43. };
复制代码



后来在:ShapeDrawable文件中发现如下代码,这应该才是Cylinder的实现吧??:
  1. void DrawShapeVisitor::drawCylinderBody(unsigned int numSegments, float radius, float height)
  2. {
  3.     const float angleDelta = 2.0f*osg::PI/(float)numSegments;
  4.     const float texCoordDelta = 1.0f/(float)numSegments;

  5.     const float r = radius;
  6.     const float h = height;

  7.     float basez = -h*0.5f;
  8.     float topz = h*0.5f;

  9.     float angle = 0.0f;
  10.     float texCoord = 0.0f;

  11.     bool drawFrontFace = _hints ? _hints->getCreateFrontFace() : true;
  12.     bool drawBackFace = _hints ? _hints->getCreateBackFace() : false;

  13.     // The only difference between the font & back face loops is that the
  14.     //  normals are inverted and the order of the vertex pairs is reversed.
  15.     //  The code is mostly duplicated in order to hoist the back/front face
  16.     //  test out of the loop for efficiency

  17.     GLBeginEndAdapter& gl = _state.getGLBeginEndAdapter();

  18.     gl.Begin(GL_QUAD_STRIP);

  19.     if (drawFrontFace) {

  20.       for(unsigned int bodyi=0;
  21.           bodyi<numSegments;
  22.           ++bodyi,angle+=angleDelta,texCoord+=texCoordDelta)
  23.       {
  24.           float c = cosf(angle);
  25.           float s = sinf(angle);

  26.           gl.Normal3f(c,s,0.0f);

  27.           gl.TexCoord2f(texCoord,1.0f);
  28.           gl.Vertex3f(c*r,s*r,topz);

  29.           gl.TexCoord2f(texCoord,0.0f);
  30.           gl.Vertex3f(c*r,s*r,basez);
  31.       }

  32.       // do last point by hand to ensure no round off errors.
  33.       gl.Normal3f(1.0f,0.0f,0.0f);

  34.       gl.TexCoord2f(1.0f,1.0f);
  35.       gl.Vertex3f(r,0.0f,topz);

  36.       gl.TexCoord2f(1.0f,0.0f);
  37.       gl.Vertex3f(r,0.0f,basez);
  38.     }

  39.     if (drawBackFace) {
  40.       for(unsigned int bodyi=0;
  41.           bodyi<numSegments;
  42.           ++bodyi,angle+=angleDelta,texCoord+=texCoordDelta)
  43.       {
  44.           float c = cosf(angle);
  45.           float s = sinf(angle);

  46.           gl.Normal3f(-c,-s,0.0f);

  47.           gl.TexCoord2f(texCoord,0.0f);
  48.           gl.Vertex3f(c*r,s*r,basez);

  49.           gl.TexCoord2f(texCoord,1.0f);
  50.           gl.Vertex3f(c*r,s*r,topz);
  51.       }

  52.       // do last point by hand to ensure no round off errors.
  53.       gl.Normal3f(-1.0f,0.0f,0.0f);

  54.       gl.TexCoord2f(1.0f,0.0f);
  55.       gl.Vertex3f(r,0.0f,basez);

  56.       gl.TexCoord2f(1.0f,1.0f);
  57.       gl.Vertex3f(r,0.0f,topz);
  58.     }

  59.     gl.End();
  60. }
复制代码


thanks~

该用户从未签到

 楼主| 发表于 2014-4-22 13:37:48 | 显示全部楼层
问题(3) :这种贴图方法,会对圆柱体顶端和底端也贴图,如何去除。?
这个问题解决如下,将setCreateBottom和setCreateTop 设置为空,即可。
多谢buaahc 和ysm两位的指教。
如果遇到相同的问题初学者,可以如下解决。

  1.         osg::TessellationHints* hints = new osg::TessellationHints;
  2.         hints->setDetailRatio(0.5f);
  3.         hints->setCreateBody(true);
  4.         hints->setCreateBottom(false);
  5.         hints->setCreateTop(false);
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

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

联系我们

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