手动计算球面顶点的坐标,纹理坐标,来画球并贴纹理

其中createSphereGeom()函数的的二个参数为18,意思是在经纬度上每10度设一个点,因为经度一共是180度,180/18=10,相当于横着把球分为18份,每一份相当于一个圆盘,然后再把圆盘分为18*2=36份,每一份相当于一个扇形。

由于要贴纹理,所以在实现的时候,最上面的一个顶点是36+1=37个顶点重合了,最下面的一个顶点一样,中间每一圈的最开始的顶点和最后一个顶点重合,每一圈都有36+1=37个顶点,总共有(36+1)*(18+1)=703个顶点。

为什么每一圈是37个顶点而不是36,其实如果不贴纹理就只是画球,那36个顶点就可以了,但是纹理是一张矩形的图片,你要把一个矩形上的每个点映射到球面上,那每一圈就需要多一个点。

如下图,把一张纸分为4份,上面有5个点,再把这张纸卷成圆筒,最左边和最右边的点重合了,看起来就只有4个点了。当然如果不需要贴纹理,那就不用重合的点了。

纹理的坐标原点是在左下角,为了和物体位置的坐标xyz区分,纹理坐标叫做str,s相当于x,t相当y。s是横坐标,t是纵坐标。

下面看完整的代码,想要运行,你需要安装好osg

#include <math.h>

#include <osg/Geode>
#include <osg/Group>
#include <osg/Vec3>
#include <osg/Geometry>
#include <osg/ref_ptr>
#include <osg/Vec2>
#include <osg/Texture2D> #include <osgDB/ReadFile> #include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers> #include <osgGA/StateSetManipulator> /**
@brief : 创建一个球的几何节点
@param : [in] dRadius 球的半径
@param : [in] iHint 每180/iHint度设置一个点,默认18
@return: 一个球的osg::Geometry*
*/
osg::Geometry* createSphereGeom(double dRadius = 1., int iHint = 18)
{
osg::ref_ptr<osg::Geometry> rpGeom = new osg::Geometry;
osg::ref_ptr<osg::Vec3Array> rpVertexes = new osg::Vec3Array;//顶点数组
osg::ref_ptr<osg::Vec3Array> rpNormal = new osg::Vec3Array;//法线数组
osg::ref_ptr<osg::Vec2Array> rpTexCoord = new osg::Vec2Array;//纹理数组 for (int i = 0; i <= iHint; i++)//从上到下添加点,有等于号是为了之后贴纹理时可以和图片的点一一对应
{
for (int j = 0; j <= iHint * 2; j++)//逆时针添加点
{
osg::Vec3 vec3VertexT(
sin(osg::PI*i / iHint)*cos(osg::PI*j / iHint),
sin(osg::PI*i / iHint)*sin(osg::PI*j / iHint),
cos(osg::PI*i / iHint));//球面坐标公式
rpVertexes->push_back(vec3VertexT * dRadius);//添加顶点
rpNormal->push_back(vec3VertexT);//添加法线
rpTexCoord->push_back(osg::Vec2(double(j) / 2.0 / iHint
, 1 - double(i) / iHint));//添加纹理坐标
}
} osg::ref_ptr<osg::Vec4Array> rpColors = new osg::Vec4Array;
rpColors->push_back(osg::Vec4(1.0, 1.0, 1.0, 1.0)); rpGeom->setVertexArray(rpVertexes);
rpGeom->setNormalArray(rpNormal);
rpGeom->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
rpGeom->setColorArray(rpColors);
rpGeom->setColorBinding(osg::Geometry::BIND_OVERALL);
rpGeom->setTexCoordArray(0, rpTexCoord); //添加图元
osg::ref_ptr<osg::DrawElementsUInt> rpFace = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLE_STRIP);
for (int i = 0; i < iHint; i++) {
for (int j = 0; j <= iHint * 2; j++) {
rpFace->push_back(i*(iHint * 2 + 1) + j);
rpFace->push_back((i + 1)*(iHint * 2 + 1) + j);
}
}
rpGeom->addPrimitiveSet(rpFace); return rpGeom.release();
} /**
@brief : 给球贴纹理
@param : [in/out] pNode 球的节点
@return:
*/
void setTex(osg::Node* pNode)
{
osg::ref_ptr<osg::Image> rpImage = osgDB::readImageFile("../star/moon.jpg");
osg::ref_ptr<osg::Texture2D> rpTexture = new osg::Texture2D(); rpTexture->setImage(rpImage);
rpTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);//设置S方向的环绕模式
rpTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);//设置R方向的环绕模式
//rpTextureT->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_NEAREST);
//rpTextureT->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); osg::ref_ptr<osg::StateSet> pState = pNode->getOrCreateStateSet();
pState->setTextureAttributeAndModes(0, rpTexture, osg::StateAttribute::ON);
} int main(int argc, char** argv)
{
osg::ref_ptr<osgViewer::Viewer> rpViewer = new osgViewer::Viewer();
osg::ref_ptr<osg::Group> rpRoot = new osg::Group(); osg::ref_ptr<osg::Geode> rpGeode = new osg::Geode;
rpGeode->addChild(createSphereGeom(1., 45));
setTex(rpGeode);//在球上贴纹理 rpRoot->addChild(rpGeode);
rpViewer->setSceneData(rpRoot); rpViewer->addEventHandler(new osgGA::StateSetManipulator(rpViewer->getCamera()->getOrCreateStateSet()));//添加w事件处理
rpViewer->addEventHandler(new osgViewer::StatsHandler);//添加s事件处理 rpViewer->run();
return 0;
}

程序运行截图

未贴纹理的球:

隐藏表面,只显示线的球,即按w键后的球:

只显示点的球:

最新文章

  1. UEditor上传图片到七牛云储存(c#)
  2. jquery实时监测手机号是否符合规则,并根据手机号检测结果将提交按钮设为不同状态
  3. Chkrootkit Sourcecode Learning
  4. 部署测试环境(ubuntu+mysql+tomcat)
  5. 非Page类使用session(Httpcontext.session和page.session区别)
  6. Controlling Access in Java
  7. JAVA编程相关:eclipse如何导入已有工程
  8. 谈一谈最近学了一段时间的node.js
  9. Mvc 流程调用分析
  10. 洛谷P1446 [HNOI2008]Cards
  11. ESXi去掉 SSH已经启用的警告信息
  12. what&#39;s the python之可迭代对象、迭代器与生成器(附面试题)
  13. OAuth和OpenID的区别
  14. Kylin介绍,功能特点【转】
  15. Centos 6.9 安装Rabbitmq
  16. 关于chrome插件编写的小结
  17. 【Android】5.4 下拉框(Spinner)
  18. Oracle数据类型number
  19. Python进阶内容(一)--- 高阶函数 High order function
  20. wait与waitpid

热门文章

  1. 拖拽方式生成Vue用户界面
  2. python函数之有参装饰器
  3. Dynamics CRM调用选择用户弹窗
  4. 敏捷史话(十四):敏捷之峰的攀登者 —— Jim Highsmith
  5. Java刷题-list
  6. 基本dos命令
  7. 13- jmeter性能测试案例
  8. 【CompletableFuture】CompletableFuture中join()和get()方法的区别
  9. 【并发编程】Java中的锁有哪些?
  10. Day002 编译型和解释型语言