一、目的
1、画一个球体;
二、程序运行结果
球体
三、球体的生成
球面坐标计算示意图
1、将球体横向向切成30片, 纵向切30片,共900个点,见示意图
2、循环生成900个点的空间坐标(x,y,z),球面上点C的坐标
3、 x= R * cos(NumAngleHy) * cos(NumAngleZx)
4、 y = R * sin(NumAngleHy)
5、 z = R * cos(NumAngleHy) * sin(NumAngleZx)
6、将900个点按顺序存入顶点缓冲区,
7、将相邻的三个点的顺序索引值存入索引缓冲区。
8、调用OpenGL动态管线进行渲染。
四、glPolygonMode函数
功能:用于控制多边形的显示方式
glPolygonMode是一个函数,原型是:void glPolygonMode(GLenum face,GLenum mode);
face这个参数确定显示模式将适用于物体的哪些部分,控制多边形的正面和背面的绘图模式:
GL_FRONT表示显示模式将适用于物体的前向面(也就是物体能看到的面)
GL_BACK表示显示模式将适用于物体的后向面(也就是物体上不能看到的面)
GL_FRONT_AND_BACK表示显示模式将适用于物体的所有面
mode这个参数确定选中的物体的面以何种方式显示(显示模式):
GL_POINT表示显示顶点,多边形用点显示
GL_LINE表示显示线段,多边形用轮廓显示
GL_FILL表示显示面,多边形采用填充形式
五、源代码
"""
程序名称:GL_DrawSphere01.py
编程: dalong10
功能: 画一个球体
参考资料:
"""
import myGL_Funcs #Common OpenGL utilities,see myGL_Funcs.py
import sys, random, math
import OpenGL
from OpenGL.GL import *
from OpenGL.GL.shaders import *
import numpy
import numpy as np
import glfw
strVS = """
#version 330 core
layout(location = 0) in vec3 position;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
uniform float a;
uniform float b;
uniform float c;
uniform float Rx;
uniform float Ry;
uniform float Rz;
uniform float theta1;
void main(){
mat4 rot1=mat4(vec4(1.0, 0.0,0.0,0),
vec4(0.0, 1.0,0.0,0),
vec4(0.0,0.0,1.0,0.0),
vec4(a,b,c,1.0));
mat4 rot3=mat4( vec4(cos(theta1)+Rx*Rx*(1-cos(theta1)), Rx*Ry*(1-cos(theta1))-Rz*sin(theta1), Rx*Rz*(1-cos(theta1))+Ry*sin(theta1), 0),
vec4(Rx*Ry*(1-cos(theta1))+Rz*sin(theta1),cos(theta1)+Ry*Ry*(1-cos(theta1)),Ry*Rz*(1-cos(theta1))-Rx*sin(theta1),0),
vec4(Rx*Rz*(1-cos(theta1))-Ry*sin(theta1),Ry*Rz*(1-cos(theta1))+Rx*sin(theta1),cos(theta1)+Rz*Rz*(1-cos(theta1)), 0.0),
vec4(0.0, 0.0,0.0, 1.0));
gl_Position=uPMatrix * uMVMatrix* rot1 *rot3 *vec4(position.x, position.y, position.z, 1.0);
}
"""
strFS = """
#version 330 core
out vec3 color;
void main(){
color = vec3(0,1,1);
}
"""
VIEW=np.array([-0.8, 0.8, -0.8, 0.8, 1.0, 20.0]) # 视景体的left/right/bottom/top/near/far六个面
SCALE_K=np.array([1.0, 1.0, 1.0]) # 模型缩放比例
cameraPos=np.array([0.0, 0.0, 1.2]) # 眼睛的位置(默认z轴的正方向)
cameraFront=np.array([0.0, 0.0, 0.0]) # 瞄准方向的参考点(默认在坐标原点)
cameraUp=np.array([0.0, 1.0, 0.0]) # 定义对观察者而言的上方(默认y轴的正方向)
WIN_W, WIN_H = 640, 480 # 保存窗口宽度和高度的变量
class FirstSphere:
def __init__(self, cube_verticeside ,indices):
# load shaders
self.program = myGL_Funcs.loadShaders(strVS, strFS)
glUseProgram(self.program)
self.vertIndex = glGetAttribLocation(self.program, b"position")
cube_vertices = cube_verticeside
self.indices = indices
# set up vertex array object (VAO)
self.vao = glGenVertexArrays(1)
glBindVertexArray(self.vao)
# set up VBOs
vertexData = numpy.array(cube_vertices, numpy.float32)
self.vertexBuffer = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, self.vertexBuffer)
glBufferData(GL_ARRAY_BUFFER, 4*len(vertexData), vertexData, GL_STATIC_DRAW)
# set up EBOs
indiceData = numpy.array(indices, numpy.int32)
self.eboID = glGenBuffers(1)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,self.eboID)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 4 *len(indiceData), indiceData, GL_STATIC_DRAW)
# enable arrays
glEnableVertexAttribArray(self.vertIndex)
# Position attribute
glBindBuffer(GL_ARRAY_BUFFER, self.vertexBuffer)
glVertexAttribPointer(self.vertIndex, 3, GL_FLOAT, GL_FALSE, 0,None)
# unbind VAO
glBindVertexArray(0)
glBindBuffer(GL_ARRAY_BUFFER, 0)
def render(self, xx, yy, zz, Rx,Ry,Rz,r1,pMatrix,mvMatrix):
# use shader
glUseProgram(self.program)
# set proj matrix
glUniformMatrix4fv(glGetUniformLocation(self.program, 'uPMatrix'),
1, GL_FALSE, pMatrix)
# set modelview matrix
glUniformMatrix4fv(glGetUniformLocation(self.program, 'uMVMatrix'),
1, GL_FALSE, mvMatrix)
glUniform1f(glGetUniformLocation(self.program, "a"), xx)
glUniform1f(glGetUniformLocation(self.program, "b"), yy)
glUniform1f(glGetUniformLocation(self.program, "c"), zz)
glUniform1f(glGetUniformLocation(self.program, "Rx"), Rx)
glUniform1f(glGetUniformLocation(self.program, "Ry"), Ry)
glUniform1f(glGetUniformLocation(self.program, "Rz"), Rz)
theta1 = r1*PI/180.0
glUniform1f(glGetUniformLocation(self.program, "theta1"), theta1)
# bind VAO
glBindVertexArray(self.vao)
# draw
glDrawElements(GL_TRIANGLES, self.indices.size, GL_UNSIGNED_INT, None)
# unbind VAO
glBindVertexArray(0)
def drawglobeVBO():
PI = 3.14159265358979323846264
statcky = 30 # 横向向切成多少片
stlicex = 30 # 纵向切多少片
R = 1.0 # 半径
angleHy = (2*PI)/statcky # 横向每份的角度 算出弧度值
angleZx = (2*PI)/stlicex; # 纵向每份的角度 算出弧度值
NumAngleHy = 0.0 # 当前横向角度
NumAngleZx = 0.0 # 当前纵向角度
x=0.0
y=0.0
z=0.0
c=numpy.array([], numpy.float32)
for j in range(statcky):
for i in range(stlicex):
NumAngleHy = angleHy*i #
NumAngleZx = angleZx*j # 起点都是轴指向的方向。根据右手定则决定转向,只要转向相同,那么两个就合适
x = R*np.cos(NumAngleHy)*np.cos(NumAngleZx)
y = R*np.sin(NumAngleHy)
z = R*np.cos(NumAngleHy)*np.sin(NumAngleZx)
c=np.hstack((c,numpy.array([x,y,z], numpy.float32) ))
return c
def drawglobeEBO():
PI = 3.14159265358979323846264
statcky = 30 # 横向向切成多少片
stlicex = 30 # 纵向切多少片
vbo = drawglobeVBO()
only = vbo.size
num = (int)((only/(3*statcky))*2)
ebo=numpy.array([], numpy.int)
for x in range(int(stlicex/2)):
for y in range(statcky):
ebo=np.hstack((ebo,numpy.array([y+x*stlicex,y+x*stlicex+1,y+x*stlicex+stlicex,y+x*stlicex+stlicex+1,y+x*stlicex+stlicex,y+x*stlicex+1])))
return ebo
#Is called whenever a key is pressed/released via GLFW
def on_key(window, key, scancode, action, mods):
if key == glfw.KEY_ESCAPE and action == glfw.PRESS:
glfw.set_window_should_close(window,1)
if __name__ == '__main__':
import sys
import glfw
import OpenGL.GL as gl
keys=numpy.zeros(1024)
deltaTime = 0.0
lastFrame = 0.0 # Time of last frame
# Initialize the library
if not glfw.init():
sys.exit()
# Create a windowed mode window and its OpenGL context
window = glfw.create_window(640, 480, "GL_DrawSphere01 ", None, None)
if not window:
glfw.terminate()
sys.exit()
# Make the window's context current
glfw.make_context_current(window)
# Install a key handler
glfw.set_key_callback(window, on_key)
PI = 3.14159265358979323846264
# 画球面
vert = drawglobeVBO()
ind = drawglobeEBO()
# Loop until the user closes the window
a=0
firstSphere1 = FirstSphere(vert,ind)
while not glfw.window_should_close(window):
currentFrame = glfw.get_time()
deltaTime = currentFrame - lastFrame
lastFrame = currentFrame
# Render here
width, height = glfw.get_framebuffer_size(window)
WIN_W, WIN_H =width, height
ratio = width / float(height)
glfw.poll_events()
gl.glViewport(0, 0, width, height)
gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); #用于控制多边形的显示方式
gl.glMatrixMode(gl.GL_PROJECTION)
gl.glLoadIdentity()
gl.glOrtho(-ratio, ratio, -1, 1, 1, -1)
gl.glMatrixMode(gl.GL_MODELVIEW)
gl.glLoadIdentity()
gl.glClearColor(0.0,0.1,0.1,1.0)
# modelview matrix
mvMatrix = myGL_Funcs.lookAt(cameraPos, cameraFront, cameraUp) # 设置视点
if WIN_W > WIN_H:
zLeft=VIEW[0] * WIN_W / WIN_H
zRight=VIEW[1] * WIN_W / WIN_H
zBottom=VIEW[2]
zTop=VIEW[3]
zNear=VIEW[4]
zFar=VIEW[5]
else:
zLeft=VIEW[0]
zRight=VIEW[1]
zBottom=VIEW[2] * WIN_H / WIN_W
zTop=VIEW[3] * WIN_H / WIN_W
zNear=VIEW[4]
zFar=VIEW[5]
pMatrix =myGL_Funcs.perspective(zLeft,zRight,zTop,zBottom, zNear, zFar)
firstSphere1.render( 0, 0, 0, 0, 1,1, a ,pMatrix, mvMatrix) #地球
# a=a+1
# if a>360:
# a=0
# Swap front and back buffers
glfw.swap_buffers(window)
# Poll for and process events
glfw.poll_events()
glfw.terminate()
六、参考资料