从头开始绘制一个球体

好久都没有更新博客了,最近在研究OpenGL图形编程,写了一些有趣的程序,分享一下. 废话少说,开始吧.

球体作为基本的几何图形在游戏程序中应用广泛,其中最为人所知的是可以作为Sky Dome模拟天空,比起Sky Box来说更加细致一些,即使加上别的特殊效果也不容易穿帮.

我们在中学的数学课上应该学过球体的参数方程

x = r * sin(angZ) * cos(angXY)

y = r * sin(angZ) * sin(angXY)

z = r * cos(angZ)

angZ是纵向夹角,angXY是横向夹角,r是半径. 想起来了吧,用这个方程可以表示球体表面上的点,对了用这个方程就可画出球体模型.

先让看一下需要定义哪些变量与函数:

#ifndef PI
#define PI 3.1415926//这个不用解释了
#endif
#ifndef PI2
#define PI2 6.2831853//2PI
#endif

class Sphere {
private:
	GLuint* vboId;
	GLuint vert,texcoord;
	GLfloat* verts;//保存顶点与法向量的指针
	GLfloat* texcoords;//保存纹理坐标的指针
	int vertNum;
public:
	Sphere(int m,int n);//m是纵向细分程度,n是横向细分程度
	~Sphere();
	void render();//渲染球体!
};

其中构造函数里面的m与n分别表示纵向与横向的细分程度,值越大则球体看上去越精细. GLuint,GLfloat是OpenGL的变量类型,相当于C++中的unsigned int和float.

接着来看一下构造球体最主要的部分:

	vertNum=m*n*4;//顶点总数
	verts=new GLfloat[vertNum*3];//每个顶点有xyz三个分量,因此*3
	texcoords=new GLfloat[vertNum*2];//每个顶点的纹理坐标有uv两个分量,因此*2

	float stepAngZ=PI/m;//纵向角度每次增加的值
	float stepAngXY=PI2/n;//横向角度每次增加的值
	float angZ=0.0;//初始的纵向角度
	float angXY=0.0;//初始的横向角度

	int index=0;
	int indexTex=0;
	for(int i=0;i<m;i++) {
		for(int j=0;j<n;j++) {
                        //构造一个顶点
                        float x1=sin(angZ)*cos(angXY);
			float y1=sin(angZ)*sin(angXY);
			float z1=cos(angZ);
			verts[index]=x1; index++;
			verts[index]=y1; index++;
			verts[index]=z1; index++;
			float v1=angZ/PI;
			float u1=angXY/PI2;
			texcoords[indexTex]=u1; indexTex++;
			texcoords[indexTex]=v1; indexTex++;

			float x2=sin(angZ+stepAngZ)*cos(angXY);
			float y2=sin(angZ+stepAngZ)*sin(angXY);
			float z2=cos(angZ+stepAngZ);
			verts[index]=x2; index++;
			verts[index]=y2; index++;
			verts[index]=z2; index++;
			float v2=(angZ+stepAngZ)/PI;
			float u2=angXY/PI2;
			texcoords[indexTex]=u2; indexTex++;
			texcoords[indexTex]=v2; indexTex++;

			float x3=sin(angZ+stepAngZ)*cos(angXY+stepAngXY);
			float y3=sin(angZ+stepAngZ)*sin(angXY+stepAngXY);
			float z3=cos(angZ+stepAngZ);
			verts[index]=x3; index++;
			verts[index]=y3; index++;
			verts[index]=z3; index++;
			float v3=(angZ+stepAngZ)/PI;
			float u3=(angXY+stepAngXY)/PI2;
			texcoords[indexTex]=u3; indexTex++;
			texcoords[indexTex]=v3; indexTex++;

			float x4=sin(angZ)*cos(angXY+stepAngXY);
			float y4=sin(angZ)*sin(angXY+stepAngXY);
			float z4=cos(angZ);
			verts[index]=x4; index++;
			verts[index]=y4; index++;
			verts[index]=z4; index++;
			float v4=angZ/PI;
			float u4=(angXY+stepAngXY)/PI2;
			texcoords[indexTex]=u4; indexTex++;
			texcoords[indexTex]=v4; indexTex++;

			angXY+=stepAngXY;
		}
		angXY=0.0;//每次横向到达2PI角度则横向角度归0
		angZ+=stepAngZ;
	}

通过增加固定角度来构造球体网格,至于为什么球体的法向量与球体表面的顶点坐标是一致的,请看以下手绘:

明白了吧,p点上的法向量就是从原点到p点的向量,简单吧.

接着是纹理坐标的计算,既然横向夹角的范围是[0,2PI],纵向夹角的坐标是[0,PI],纹理坐标的范围是[0,1],那么把每个顶点的横向与纵向的夹角对应的值按比例变到[0,1]就能够计算出每个顶点的纹理坐标了.

嗯, 既然顶点,法向量,纹理坐标都有了,那么把这些数据都提交到显存中去,然后渲染出图像吧.

嗯,结果就是这样. 圆吧?

以上结果使用OpenGL渲染,使用DirectX也能够实现相同的效果.

时间: 2024-08-26 19:39:29

从头开始绘制一个球体的相关文章

从头开始绘制一个圆锥体

opengl帮助库glu里有一个对象叫做二次几何体,可以用来给球体圆锥体建模,然而在opengles中不能使用glu库,那么我们只能自己写方法替代它了,上次给球体建了模,这次应该给圆锥体建模了. 圆锥体是平面上的一个圆以及它的所有切线和平面外一点确定的平面围成的几何体,圆被称为底面,顶点被称为尖端,定义听上去有些复杂,那么看图: 嗯,懂了吧.其实它是一种特殊情况,如果尖端是一个圆面的话那么它就是一个截头圆锥体,顶面半径为0的截头圆锥体就是圆锥体了. 先来看下头文件是怎么定义的吧: class C

osg绘制一个球体

//By smells2 at Lab 2012-02-21#include <osg/Group>#include <osg/Geode>#include <osg/ShapeDrawable>#include <osg/Texture2D>#include <osgViewer/Viewer>#include <osgDB/readfile> #include <osg/PositionAttitudeTransform&g

Three.js 第一篇:绘制一个静态的3D球体

第一篇就画一个球体吧 首先我们知道Three.js其实是一个3D的JS引擎,其中的强大之处就在于这个JS框架并不是依托于JQUERY来写的.那么,我们在写这一篇绘制3D球体的文章的时候,应该注意哪些地方呢?下面我就来一一列举 1.场景. 场景是什么,说得简单一点,场景就是一个canvas ,我们就是要在Canvas上面实现3D效果的画面而已.场景和容器,相机是息息相关的,我们就拿拍戏来说,假如我们需要演一个古装剧的撕逼场景,那么,我们需要的道具其中之一就是一个相机. 2.容器 就是承载球体的DI

使用CAD编辑器快速绘制三维球体

使用迅捷CAD编辑器快速绘制三维球体.我们都知道CAD绘图设计都是先从简单的图形开始,一点一点练习绘制的,正所谓熟能生巧.在日常的CAD绘图工作中,我们常常需要绘制各种各样不同的CAD图形,其中就包括绘制三维球体.那么如何快速绘制一个三维球体呢?具体演示步骤如下: 步骤一:首先,我们先在电脑端下载安装迅捷CAD 编辑器专业版. 步骤二:运行迅捷CAD编辑器专业版软件,点击执行"绘图"-"平面模型网络"-"球体"命令. 步骤三:此时CAD绘图区域会

从头开始搭建一个dubbo+zookeeper平台 【转】

本篇主要是来分享从头开始搭建一个dubbo+zookeeper平台的过程,其中会简要介绍下dubbo服务的作用.   注册中心的选择   dubbo支持多种类型的注册中心: 这里我们选择zookeeper,其实类型的优点缺点可详细查看文档. 1:zookeeper的安装,还是采用docker这一招鲜的run命令来安装zookeeper docker run -dit --name zookeeper --hostname zookeeper-host -v /data:/data -p 2181

从头开始搭建一个dubbo+zookeeper平台

本篇主要是来分享从头开始搭建一个dubbo+zookeeper平台的过程,其中会简要介绍下dubbo服务的作用. 首先,看下一般网站架构随着业务的发展,逻辑越来越复杂,数据量越来越大,交互越来越多之后的常规方案演进历程. 其次,当服务越来越多之后,我们需要做哪些服务治理? 最后,是dubbo的架构图   注册中心的选择   dubbo支持多种类型的注册中心: Multicast注册中心 Zookeeper注册中心 Redis注册中心 Simple注册中心 这里我们选择zookeeper,其实类型

OpenGl 绘制一个立方体

OpenGl 绘制一个立方体 为了绘制六个正方形,我们为每个正方形指定四个顶点,最终我们需要指定6*4=24个顶点.但是我们知道,一个立方体其实总共只有八个顶点,要指定24次,就意味着每个顶点其实重复使用了三次,这样可不是好的现象.最起码,像上面这样重复烦琐的代码,是很容易出错的.稍有不慎,即使相同的顶点也可能被指定成不同的顶点了. 如果我们定义一个数组,把八个顶点都放到数组里,然后每次指定顶点都使用指针,而不是使用直接的数据,这样就避免了在指定顶点时考虑大量的数据,于是减少了代码出错的可能性.

四、绘制一个点

上次我们介绍了如何在<canvas>中使用WebGL,以及几个基础的WebGL函数:实现了背景色的重置:为了扩展方便,我们把上次的代码做了些改动,将绘制图形的js独立成文件,这样我们只关注与这个js文件的编写:以后除非HTML文件发生变化,我们就跳过它,直接讨论JavaScript代码. 1 <!doctype html> 2 <html> 3 <head> 4 <meta charset="UTF-8"> 5 <met

GDI+学习笔记(五)绘制一个正方体

本文将介绍如何利用GDI+绘制一个正方体. (一)准备阶段 想象一下,高中的时候,我们在学立体几何的时候是怎样画一个正方体的,我们在一张纸上利用投影的思路将其绘制在一张纸上,对吧,这计算投影的部分,我们暂且忽略.下图是我用windows的画图绘制的一个正方体: 我们计算出这些点在平面上的坐标如下: Point A(100,200); Point B(200,200); Point C(100,300); Point D(200,300); Point E(100+50*1.414, 200-50