python 曲面_Python之OpenGL笔记(35):曲面物体的构建

一、目的

1、曲面物体的构建画球体;

2、棋盘纹理着色器应用;

二、程序运行结果

棋盘纹理着色器应用

三、曲面物体的构建基本原理

吴亚峰《OpenGL ES 3.x游戏开发》(上卷)内容

OpenGL 中任何形状的 3D 物体都是用三角形拼凑而成的,因此,构建ᴢ面物体最重要的就是找到将曲面恰当拆分成三角形的策略。最基本的策略是首先按照一定的规则将物体按行和列两个方向进行拆分,这时就可以得到很多的小四边形。然后再将每个小四边形拆分成两个三角形即可。

球面首先被按照纬度(行)和经度(列)的方向拆分成了很多的小四边形,每个小四边形又被拆分成两个小三角形。

这种拆分方式下,三角形中每个顶点的坐标都可以用解析几何的公式方便地计算出来,具体情况如下。

x = R×cosα×cosβ;

y = R×cosα×sinβ;

z = R×sinα

四、棋盘纹理着色器

棋盘纹理着色器是一种非常简单的着色器,其原理如下图所示:

具体的着色策略为,若片元位于黑色小方块中,就将该片元的颜色设置为红色;若片元位于白棋盘色小方块中,则将片元的颜色设置为白色,具体计算方法如下所列。

首先计算出当前片元 x、 y、 z 坐标对应的行数(x 轴)、层数(y 轴)及列数(z 轴)。

如果行数、层数、列数之和为奇数,则片元为红色;若和为偶数,则片元为白色。

五、源代码

"""

程序名称:GL_DrawBall02.py

编程: dalong10

功能: 球体构建、棋盘着色器应用的实现

参考资料: 《OpenGL ES 3.x游戏开发》(上卷)吴亚峰

"""

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

from pyrr import Quaternion, matrix44, Vector3

strVS = """

#version 330 core

layout(location = 0) in vec3 position;

uniform mat4 uMVMatrix;

uniform mat4 uPMatrix;

uniform float Rx;

uniform float Ry;

uniform float Rz;

uniform float theta1;

out vec3 vPosition ; //用于传递给片元着色器的顶点位置

void main(){

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* rot3 *vec4(position.x, position.y, position.z, 1.0);

//将顶点的位置传给片元着色器

vPosition = position;//将原始顶点位置传递给片元着色器

}

"""

strFS = """

#version 330 core

in vec3 vPosition;//接收从顶点着色器过来的顶点位置

out vec4 fragColor;//输出的片元颜色

void main(){

vec3 color;

float n = 8.0;//外接立方体每个坐标轴方向切分的份数

float uR=1.0 ;

float span = 2.0*uR/n;//每一份的尺寸(小方块的边长)

int i = int((vPosition.x + uR)/span);//当前片元位置小方块的行数

int j = int((vPosition.y + uR)/span);//当前片元位置小方块的层数

int k = int((vPosition.z + uR)/span);//当前片元位置小方块的列数

//计算当前片元行数、层数、列数的和并对2取模

int whichColor = int(mod(float(i+j+k),2.0));

if(whichColor == 1) {//奇数时为红色

color = vec3(0.678,0.231,0.129);//红色

}

else {//偶数时为白色

color = vec3(1.0,1.0,1.0);//白色

}

//将计算出的颜色传递给管线

fragColor=vec4(color,0);

}

"""

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, 30]) # 眼睛的位置(默认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 ):

# load shaders

self.program = myGL_Funcs.loadShaders(strVS, strFS)

glUseProgram(self.program)

self.vertIndex = glGetAttribLocation(self.program, b"position")

self.cube_vertices = cube_verticeside

# set up vertex array object (VAO)

self.vao = glGenVertexArrays(1)

glBindVertexArray(self.vao)

# set up VBOs

vertexData = numpy.array(self.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)

# 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, 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, "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

glDrawArrays(GL_TRIANGLES,0,len(self.cube_vertices) )

# 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 # 起点都是轴指向的方向。根据右手定则决定转向,只要转向相同,那么两个就合适

x0 = R*np.cos(NumAngleHy)*np.cos(NumAngleZx)

y0 = R*np.cos(NumAngleHy)*np.sin(NumAngleZx)

z0 = R*np.sin(NumAngleHy)

x1 = R*np.cos(NumAngleHy)*np.cos(NumAngleZx+angleZx)

y1 = R*np.cos(NumAngleHy)*np.sin(NumAngleZx+angleZx)

z1 = R*np.sin(NumAngleHy)

x2 = R*np.cos(NumAngleHy+angleHy)*np.cos(NumAngleZx+angleZx)

y2 = R*np.cos(NumAngleHy+angleHy)*np.sin(NumAngleZx+angleZx)

z2 = R*np.sin(NumAngleHy+angleHy)

x3 = R*np.cos(NumAngleHy+angleHy)*np.cos(NumAngleZx)

y3 = R*np.cos(NumAngleHy+angleHy)*np.sin(NumAngleZx)

z3 = R*np.sin(NumAngleHy+angleHy)

c=np.hstack((c,numpy.array([x1,y1,z1], numpy.float32) ))

c=np.hstack((c,numpy.array([x3,y3,z3], numpy.float32) ))

c=np.hstack((c,numpy.array([x0,y0,z0], numpy.float32) ))

c=np.hstack((c,numpy.array([x1,y1,z1], numpy.float32) ))

c=np.hstack((c,numpy.array([x2,y2,z2], numpy.float32) ))

c=np.hstack((c,numpy.array([x3,y3,z3], numpy.float32) ))

return c

#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_DrawBall02 ", 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()

# Loop until the user closes the window

a=0

firstSphere1 = FirstSphere(vert)

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 = matrix44.create_look_at(cameraPos, cameraFront, cameraUp,None) # 设置视点

pMatrix = matrix44.create_perspective_projection_from_bounds(-ratio*1.0, ratio*1.0, -1, 1,20,100,None)

firstSphere1.render( 0, 1,1, a ,pMatrix, mvMatrix) #球

# Swap front and back buffers

glfw.swap_buffers(window)

# Poll for and process events

glfw.poll_events()

glfw.terminate()

六、参考资料

1、大龙10的简书:https://www.jianshu.com/p/49dec482a291

2、吴亚峰《OpenGL ES 3.x游戏开发》(上卷)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/434904.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

了解PRACK

概述SIP定义了两种应答:临时(provisional)和最终(final)。最终应答传送的是请求处理的结果,是可靠性的(reliably)。而临时应答传送的是处理过程的信息,由RFC3261是非可靠的。但是由现…

Silverlight实例教程 - Out of Browser开篇

众所周知,学习一门IT技术,最关键的是实践,无论是软件开发还是网络调试,只要在真实环境下勤于动手和思考,很快就能掌握一门技术,Silverlight也不例外。为了帮助更多朋友快速学习掌握Silverlight应用开发&…

河流水质指标预测与不确定性分析:机器学习模型的比较研究--文献阅读

电导率 (EC)、氢气功率 (pH)、溶解氧 (DO)、总溶解固体 (TDS)、硫酸盐 (SO4)、镁 (Mg)、氯 (Cl)、总大肠菌群 (TC) 和生化需氧量 (BOD) DO、BOD、化学需氧量 (COD)、pH、硝酸盐 (NO3) 和悬浮固体 (SS)

python科学计算三剑客_1-python数据分析-数据分析介绍、数据分析三剑客之NumPy

数据分析三剑客numpypandas(重点)matplotlibnumpy模块NumPy(Numerical Python) 是 Python 语言中做科学计算的基础库。侧重在于数值计算,也是大部分Python科学计算库的基础,多用于在大型、多维数组上执行的数值运算。重点numpy数组的创建numpy索引和切片…

SIP可靠性(SIP Reliability)

根据RFC3261,SIPUA必须支持TCP及UDP底层传输协议。这两种方式除了使用方式不一样之外,对SIP协议自身的影响主要体现在可靠性处理上。 SIP可靠性机制主要是为了支持不可靠传输层协议,如UDP。当SIP使用的传输层协议为TCP或TLS时,这种…

可以无限增加iPhone 的图标吗?

可以无限增加iPhone 的图标吗?iPhone屏幕上每个图标都对应一个应用程序,目前苹果商店中应用程序数量已经超过40万个,我们又能在手机里放多少呢?有人可能会说那要取决于iPhone的存储容量有多大,确实如此,那么如果假设空…

在日本山区流域使用支持向量机和 bagging、boosting 和 stacking 集成机器学习框架改进滑坡评估--文献阅读

为了在基于过程的模型中准确表示边坡稳定性,有必要包含大量涉及滑坡几何形状和内部结构的局部特征的特征。这包括但不限于斜坡的分层和不连续性、运动裂缝、裂片、陡坡、地垒/地堑结构、降雨、空气和土壤温度、土壤水分含量、许多点的地下水位、地表和深度但是&…

android 蒙版图片带拖动_推荐一个好用小巧的Android引导蒙版(浮层)库

更新:目前该库已更新v2.0版本,修改了调用api,详细使用可以看:可能是最好用的Android引导层库前言每当一个项目开发一个新功能,总会想办法及时让用户得知有这样一个新功能,这时通常会采用引导页或者蒙版(浮层…

用户代理行为

概述 用户代理分两种:UAC和UAS。区分的依据在于请求方和响应方。 当一个请求发生之时,即使用某个方法,根据请求方和响应方产生了UAC和UAS,从而可以建立起事务(Transaction)来。所以UAC和UAS是对某个事务而言…

AX 2009 界面伸缩功能

界面伸缩功能 在一个界面下,放置多个Grid之后,数据太多,要有个能推拉伸缩的功能,如下图: 中间横条可以上下拉动,折叠处可以关闭显示整个Grid 横条要代码实现,折叠只要设置一下Group就行。 纵向空…

使用增强回归树和随机森林模型进行溪流水质预测--文献阅读

流域特征和气候变量(例如地形、土壤、气候数据)也会影响河流水质。例如,陡坡可能会通过将污染物转移到溪流中来影响溪流水质,从而导致水质恶化。同样,土壤特性也会影响水质。例如,以母岩为主的流域显示出较…

解决方案架构师我需要懂代码吗_架构师不写代码,能行吗?

原标题:架构师不写代码,能行吗?从什么时候起,技术角色的提升就意味着脱离技术与交付?CTO 不写代码已经引起诸多争议了,架构师也不写代码,能行吗?就目前看来这似乎没什么问题。毕竟&a…

机器学习在地质灾害的文章--文献阅读

第一篇 Improved landslide assessment using support vector machine with bagging, boosting, and stacking ensemble machine learning framework in a mountainous watershed, Japan | SpringerLinkHeavy rainfall in mountainous terrain can trigger numerous landslide…

取消一个请求(Cancel)

CANCEL请求,就像名字所说的,是用来取消客户端发起的上一个请求的。 CANCEL请求UAS去终止上一个请求并且对上一个请求产生一个错误的应答。CANCEL对UAS已经给出终结应答的请求无效。所以,CANCEL请求的最大用处是取消需要服务器长时间处理的请求…

NYOJ88(数论)

题意明确,让计算出起始有m个金片的汉诺塔金片全部移动到另外一个针上时需要移动的最少步数是多少?(由于结果太大,现在只要求算出结果的十进制位最后六位) 解题思路:大家都很熟悉汉诺塔求移动次数公式为f(n1…

Linq 学习笔记(二)

Linq 学习笔记(二) 下面就来介绍一些查询的示例: 1。Linq查询 var racers from r in Formula1.GetChampions()where r.Wins > 15 && (r.Country "Brazil" || r.Country "Austria") select r;foreach (var …

机器学习在水文地质方面的文章--文献阅读

第一篇 Ensemble machine learning paradigms in hydrology: A review - ScienceDirecthttps://www.sciencedirect.com/science/article/pii/S0022169421003139?via%3Dihub第二篇 Stream water quality prediction using boosted regression tree and random forest models …

查询能力(SIP OPTIONS)

SIP方法OPTIONS允许一个UA来查询另外一个UA或者proxy服务器的能力。这个提供客户端一个手段来查询服务端支持的方法,内容类型,扩展,codecs等等。比如,在客户端试图在INVITE请求头中增加一个请求字段选项的时候,它并不知…

单体预聚合的目的是什么_高分子化学实验指导书-修改-2012

高分子化学实验指导书任课教师姓名:王小慧王小英所用教材:《高分子化学实验》何卫东主编中国科学技术大学出版社选读参考书:《高分子化学实验》梁晖卢江主编化学工业出版社一、教学形式1、课前,学生通过阅读参考书和《高分子化学实…

MemDC,GDI绘制注意点

最近绘制老犯同样的错误,记录下: 1.MemDC中的MemBmp大小一定要设定好,经常设小了,后面的绘不出来,同时最后dc.bitblt时,大小一定要和MemBmp 一致,同样经常是MemBmp必变了,bitblt的rcDest没变&am…