一、目的

1、实现环境光照射下的棋盘球体;

二、程序运行结果

三、光照的基本模型

   如果要用一个数学模型完全真实地描述现实世界中的光照是很难的,一方面数学模型本身可能太过复杂,另一方面复杂的模型可能导致巨大的计算量。因此,OpenGL中采用的光照模型相对现实世界进行了很大的简化,将光照分成了3种组成元素(也可以称为3个通道),包括:

  • 环境光、
  • 散射光
  • 镜面光
       具体情况如图6-5所示。

四、环境光

  环境光(Ambient)指的是从四面八方照射到物体上,全方位360°都均匀的光。其代表的是现实世界中从光源射出,经过多次反射后,各方向基本均匀的光。环境光最大的特点是不依赖于光源的位置,而且没有方向性,图6-6简单地说明了这个问题。

  从图6-6中可以看出,环境光不但入射是均匀的,反射也是各向均匀的。用于计算环境光的数学模型非常简单,具体公式如下。

环境光照射结果=材质的反射系数×环境光强度

  程序说明:片元着色器代码与前面案例的基本相同,主要是增加了接收环境光强度,以及使用环境光强度与片元本身颜色值加权计算产生最终片元颜色值的相关代码。

五、源代码

"""
程序名称:GL_DrawBall03.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, Vector3strVS = """
#version 330 core
layout(location = 0) in vec3 position;
uniform mat4 uMVMatrix;
out vec3 vPosition ;  //用于传递给片元着色器的顶点位置
out vec4 vAmbient;    //用于传递给片元着色器的环境光分量
void main(){gl_Position= uMVMatrix* vec4(position.x, position.y, position.z, 1.0);//将顶点的位置传给片元着色器vPosition = position;//将原始顶点位置传递给片元着色器//将环境光强度传给片元着色器vAmbient = vec4(0.15,0.15,0.15,1.0);}
"""strFS = """
#version 330 core
in vec3 vPosition;//接收从顶点着色器过来的顶点位置
in vec4 vAmbient;//接收从顶点着色器过来的环境光强度
out vec4 fragColor;//输出的片元颜色
void main(){vec3 color;float n = 8.0;//外接立方体每个坐标轴方向切分的份数float uR=0.8 ;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)*vAmbient;;}
"""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 shadersself.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 VBOsvertexData = 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 arraysglEnableVertexAttribArray(self.vertIndex)# Position attributeglBindBuffer(GL_ARRAY_BUFFER, self.vertexBuffer)glVertexAttribPointer(self.vertIndex, 3, GL_FLOAT, GL_FALSE, 0,None)               # unbind VAOglBindVertexArray(0)glBindBuffer(GL_ARRAY_BUFFER, 0)    def render(self,  mvMatrix):       # use shaderglUseProgram(self.program)# set modelview matrixglUniformMatrix4fv(glGetUniformLocation(self.program, 'uMVMatrix'), 1, GL_FALSE, mvMatrix)# bind VAOglBindVertexArray(self.vao)# drawglDrawArrays(GL_TRIANGLES,0,len(self.cube_vertices) )# unbind VAOglBindVertexArray(0)def drawglobeVBO():PI = 3.14159265358979323846264statcky = 30 # 横向向切成多少片stlicex = 30 # 纵向切多少片R = 0.8      # 半径angleHy =  (2*PI)/statcky  # 横向每份的角度      算出弧度值angleZx =  (2*PI)/stlicex; # 纵向每份的角度      算出弧度值NumAngleHy = 0.0 # 当前横向角度NumAngleZx = 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 sysimport glfwimport OpenGL.GL as glkeys=numpy.zeros(1024)deltaTime = 0.0lastFrame = 0.0   # Time of last frame# Initialize the libraryif not glfw.init():sys.exit()# Create a windowed mode window and its OpenGL contextwindow = glfw.create_window(640, 480, "GL_DrawBall03 ", None, None)if not window:glfw.terminate()sys.exit()# Make the window's context currentglfw.make_context_current(window)# Install a key handlerglfw.set_key_callback(window, on_key)PI = 3.14159265358979323846264# 画球面 vert = drawglobeVBO()               # Loop until the user closes the windowa=0          firstSphere1 = FirstSphere(vert)while not glfw.window_should_close(window):currentFrame = glfw.get_time()deltaTime = currentFrame - lastFrame       lastFrame = currentFrame# Render herewidth, height = glfw.get_framebuffer_size(window)WIN_W, WIN_H =width, heightratio = 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 matrixmvMatrix = 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)  model0 = matrix44.multiply(mvMatrix,pMatrix)       trans1 = matrix44.create_from_translation(Vector3([-0.6, 0, 0]))trans2 = matrix44.create_from_translation(Vector3([0.6, 0, 0]))model1 = matrix44.multiply(model0,trans1)       model2 = matrix44.multiply(model0,trans2)       firstSphere1.render( model1) #球1firstSphere1.render( model2) #球2# Swap front and back buffersglfw.swap_buffers(window)       # Poll for and process eventsglfw.poll_events()glfw.terminate()

六、参考资料

1、大龙10的简书:https://www.jianshu.com/p/49dec482a291
2、吴亚峰《OpenGL ES 3.x游戏开发》(上卷)

Python之OpenGL笔记(36):环境光下的棋盘球体相关推荐

  1. Python之OpenGL笔记(37):散射光下的棋盘球体

    一.目的 1.实现散射光照射下的棋盘球体: 二.程序运行结果 三.散射光    上一小节中给出了仅仅使用环境光进行照射的案例,读者可能觉得效果并不好.确实如此,仅仅有环境光的场景效果是很差的,没有层次 ...

  2. Python之OpenGL笔记(38):三种光照通道的合成

    一.目的 1.实现镜面光照射下的棋盘球体: 2.环境光.散射光.镜面光三种光照通道的合成 二.程序运行结果 三.镜面光    现实世界中,当光滑表面被照射时会有方向很集中的反射光.这就是镜面光(Spe ...

  3. Python之OpenGL笔记(17):键盘鼠标控制摄像机移动旋转

    一.目的 1.键盘控制摄像机自由移动: 2.鼠标控制摄像机旋转: 3.鼠标滚轮放大缩小视野. 二.程序运行结果 三.自由移动 view = lookAt(cameraPos, cameraPos + ...

  4. Python之OpenGL笔记(34):采用了顶点常量属性方法画多彩六角星

    一.目的 1.采用了顶点常量属性方法画多彩六角星: 二.程序运行结果 三.顶点常量属性    吴亚峰<OpenGL ES 3.x游戏开发>(上卷)内容    前面的很多案例中,给每一个顶点 ...

  5. Python之OpenGL笔记(26):不动点与旋转和缩放

    一.目的 1.画一组绕不动点旋转的正方体: 二.程序运行结果 三.为什么需要模型变换   OpenGL中的坐标处理过程包括模型变换.视变换.投影变换.视口变换等内容 具体过程如下图2所示:   我们在 ...

  6. Python之OpenGL笔记(33):透视投影画六角星

    一.目的 1.摄像机应用,透视投影画六角星: 二.程序运行结果 三.透视投影    吴亚峰<OpenGL ES 3.x游戏开发>(上卷)内容    现实世界中人眼观察物体时会有" ...

  7. 笔记36 笨办法学python练习43面向对象OOP的文字理解(一)

    笔记36 笨办法学python练习43面向对象OOP的文字理解(一) 先仔细看了本练习的文本,感到一个笔记写不下来这个复杂的练习过程,那就先把文字理解的部分先来完成,再用一篇笔记来完成代码的理解. 一 ...

  8. python如何下载安装glfw_Python之OpenGL笔记(1):窗口工具包GLFW的安装

    一.OpenGL简介 OpenGL(全写Open Graphics Library)是个定义了一个跨编程语言.跨平台的编程接口(Application programming interface)的规 ...

  9. Python推荐系统学习笔记(3)基于协同过滤的个性化推荐算法实战---ItemCF算法(下)

    本文在 Python推荐系统学习笔记(2)基于协同过滤的个性化推荐算法实战---ItemCF算法 一文的基础上,对其基本的ItemCF算法做出改进. 一.相关概念 1.ItemCF中,基于行为(喜好) ...

  10. Python推荐系统学习笔记(5)基于协同过滤的个性化推荐算法实战---UserCF算法(下)

    本文在 Python推荐系统学习笔记(4)基于协同过滤的个性化推荐算法实战---UserCF算法(上) 一文的基础上,对其基本的UserCF算法做出改进. 一.相关概念 1.UserCF中,基于行为( ...

最新文章

  1. Intellij IDEA 没办法创建java文件
  2. hdu4772 水模拟
  3. 个人代码库のC#千千静听 - 桌面歌词 (功能模拟)
  4. 【PC工具】图片批量添加水印工具,绿色免安装工具软件,妈妈再也不用担心我.....
  5. Server被UDP流量***
  6. vue13过滤器 debounce延迟、limitBy、filterBy、orderBy
  7. css找某个元素的下个子元素,CSS可以检测一个元素有多less个子元素?
  8. 【飞秋】在SPItemEventReceiver中使用BeforeProperties和AfterProperties
  9. 以太坊web3.js文档翻译及说明
  10. 哭!有人偷了我的漏洞报告,还冒领了奖金!
  11. UnityWebPlayer使用(2) 动态改变src
  12. matlab南方平差易,测量平差实习心得多篇
  13. 读书 曾国藩(最新图文版)
  14. Ubuntu20.04 截图工具推荐
  15. 新版Chrome设置--disable-web-security无效 解决方法
  16. nc服务器修改过ip地址,nc服务器修改过ip地址
  17. 目前数据分析师都有哪些国际认证
  18. 赞!敢闯会创的国赛新青年们!
  19. 【有利可图网】PS实战教程36:巧用PS制作人物破碎消散效果
  20. 蔬菜(vegetable)

热门文章

  1. finereport java无符合资料_Java报表工具FineReport常见的数据集报错错误代码和解释...
  2. 赤菟CH32V307 RISC-V 开发板 rt-thread 的坑 - esp8266的使用
  3. 看看五年MacBook使用经验平常都用那些软件
  4. 初学QTP系列视频教程
  5. IDEA java 中文乱码解决方法
  6. 使用TinyPNG的API进行图片压缩
  7. c语言标准库详解(五):stdio.h之直接IO/文件定位/错误处理
  8. 计算机二级vb考试题库app,全国计算机二级vb考试题库
  9. 用手机怎么制作电子版证件照
  10. H5 canvas制作数字连线效果