1.OpenGL简介
1.1简介
OpenGL(全写Open GraphicsLibrary)是指定义了一个跨编程语言、跨平台的编程接口规格的专业的图形程序接口。它用于三维图像(二维的亦可),是一个功能强大,调用方便的底层图形库。
OpenGL ES (OpenGL for Embedded Systems) 是 OpenGL 三维图形 API
的子集,针对手机、PDA和游戏主机等嵌入式设备而设计
OpenGL 与OpenGL ES区别
OpenGL ES是一个在移动平台上能够支持 OpenGL 最基本功能的精简规范, 没有四边形、多边形,无论多复杂的图形都是由点、线和三角形组成的,也去除了glBegin/glEnd等方法。
1.2 应用
- 视频 图形 图片处理
- 2D/3D游戏引擎开发
- 科学可视化,医学软件的开发
- CAD(计算机辅助技术)
- 虚拟实境(AR VR)
- AI人工智能
1.3 OpenGL ES Android 支持版本
1.4 OpenGL绘制流程
- 从OpenGL的几何图元中设置数据,用于构建形状
- 用不同的着色器对输入的图元数据执行计算操作,判断位置,颜色以及其他渲染属性
- 输入图元的数学描述 转换为与屏幕位置对应的像素片元,也称光栅化
- 针对光栅化过程产生的每个片元,执行 片元着色器,从而决定这个片元的最终颜色和位置
- 如果有必要 可以对片元执行一些额外操作(判断片元对应的对象是否可见,或者将片元的颜色与当前屏幕位置的颜色进行融合。)
2.GLSL
2.1 着色器介绍
顶点着色器—— 将虚拟空间三维坐标 映射到 屏幕显示二维坐标 +Z-buffer深度信息
模型如下:
片元着色器 ——计算每个像素的颜色和其它属性 (如光照值,贴图,阴影)
模型如下:
2.2 七大数据类型
标量—基本数据类型
- int 32位
- float 32位
- bool 8位
向量—常用于表示颜色,纹理,坐标
矩阵—常用于位移,旋转,缩放操作
- 类型 mat2 mat3 mat4
- 填充顺序从下向下,从左往右
采样器—-纹理采样 (主要用在片元着色器,在宿主(java)中初始化)
-sampler2D
-samplerCube (立体贴图,需要手动开启功能)结构体—简化运算
struct info { vec3 a; vec2 b; vec3 c; }
数组—float f[]
空类型 —void
2.3 类型修饰符
- attribute (顶点着色器特有,一般用于各个顶点各不相同的量)
- uniform (一般用于对于3D物体中所有顶点都相同的量)
- varing (一般用于顶点着色器传递到片元着色器的量)
- const (常量)
- in/out/inout (输入输出修饰符,默认in)
2.4 浮点精度
precision | 描述 | 位数(位) |
---|---|---|
lowp | 低精度 | 8 |
mediump | 中精度 | 10 |
highp | 高精度 | 16 |
3.绘制及纹理映射
3.1绘制方式
绘制方式 | 说明 |
---|---|
GL_POINTS | 点类下唯一的绘制方式,用来绘制点。 |
GL_LINES | 将着色器传入的顶点按顺序两个一组来绘制成线段 |
GL_LINES_STRIP | 按照顶点顺序连接顶点。(不封口) |
GL_LINES_LOOP | 按照顶点顺序连接顶点,并将第一个顶点和最后一个顶点相连。(封口) |
GL_TRIANGLES | 按照顶点顺序每3个点组成三角形进行绘制 |
GL_TRIANGLE_STRIP | 顶点按照顺序依次组织成三角形进行绘制, 最后实际形成的是一个三角形带。若有 |
GL_TRIANGLE_FAN | 将第一个点作为中心点其他点作为边缘点,绘制一系列组成扇形的相邻三角形 |
3.2 纹理映射
3.2.1 映射原理
- 为顶点指定纹理坐标
- 通过纹理坐标确认纹理区域
- 将选定区域根据纹理坐标映射到图元上
3.3.2 注意
- 坐标范围 0-1
- 纹理图片 宽高必须是2^n
3.3.3纹理拉伸和截取
//1=============================================================
重复拉伸
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D
,GLES20.GL_TEXTURE_WRAP_S
,GLES20.GL_REPEAT);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D
,GLES20.GL_TEXTURE_WRAP_T
,GLES20.GL_REPEAT);
//2=================================================================
截取拉伸
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_WRAP_S,
GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_WRAP_T,
GLES20.GL_CLAMP_TO_EDGE);
3.3.4纹理采样
/ | 最近点采样 | 线性采样 |
---|---|---|
基本原理 | 对应像素点 | 加权平均 |
优点 | 简单 采样快 | 线性平滑 |
缺点 | 小图映射到大图,会产生锯齿 | 容易造成线条模糊 |
【1】最近点采样
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_MIN_FILTER,
GLES20.GL_NEAREST);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D
,GLES20.GL_TEXTURE_MAG_FILTER
,GLES20.GL_NEAREST);
【2】线性采样
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_MIN_FILTER,
GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_MAG_FILTER,
GLES20.GL_LINEAR);
MIN与MAG采样
当纹理图中的一个像素对应到待映射图元上的多个片元时,采用MAG采样;反之则采用MIN采样。
通俗版:纹理比图元小,采用MAG采样纹理设置。纹理比图元大,用MIN采样纹理设置
配合:MIN与最近点,MAG与线性采样
4.光照
环境光 = 材质反射系数*环境光强度
散射光 = 材质反射系数 * 散射光强度*max(cos(入射角),0)
vec4 pointLight(vec3 normal,vec3 lightLocation, vec4 lightDiffuse){ vec3 vp=normalize(lightLocation‐(vMatrix*vec4(vPosition,1)).xyz); vec3 newTarget=normalize((vMatrix*vec4(normal+vPosition,1)).xyz ‐ (vMatrix*vec4(vPosition,1)).xyz); return lightDiffuse* max(0.0,dot(newTarget,vp)); }
镜面光 = 材质反射系数 * 镜面光强度 * max(cos(入射角)^粗糙度 ,0)
void pointLight( //定位光光照计算的方法 in vec3 normal, //法向量 inout vec4 specular, //镜面反射光分量 in vec3 lightLocation, //光源位置 in vec4 lightSpecular //镜面光强度 ){ vec3 normalTarget=aPosition+normal; vec3 newNormal=(uMMatrix*vec4(normalTarget,1)).xyz‐(uMMatrix*vec4(aPosition,1)).xyz; newNormal=normalize(newNormal); vec3 eye= normalize(uCamera‐(uMMatrix*vec4(aPosition,1)).xyz); vec3 vp= normalize(lightLocation‐(uMMatrix*vec4(aPosition,1)).xyz); vp=normalize(vp); vec3 halfVector=normalize(vp+eye); float shininess=50.0; float nDotViewHalfVector=dot(newNormal,halfVector); float powerFactor=max(0.0,pow(nDotViewHalfVector,shininess)); specular=lightSpecular*powerFactor; }
定位光
void directionalLight( in vec3 normal, inout vec4 ambient, inout vec4 diffuse, inout vec4 specular, in vec3 lightDirection, in vec4 lightAmbient, in vec4 lightDiffuse, in vec4 lightSpecular ){ ambient=lightAmbient; //环境光 //计算变之后的法向量 vec3 normalTarget=aPosition+normal; vec3 newNormal=(uMMatrix*vec4(normalTarget,1)).xyz‐(uMMatrix*vec4(aPosition,1)).xyz; newNormal=normalize(newNormal); //计算表面点到照相机的向量 vec3 eye= normalize(uCamera‐(uMMatrix*vec4(aPosition,1)).xyz); //规格化定向光方向向量 vec3 vp= normalize(lightDirection); vec3 halfVector=normalize(vp+eye); //求视线与光线的半向量 float shininess=50.0; //粗糙度 ,越小越光滑 ///散射光=材质反射系数 * 散射光强度*max(cos(入射角),0) float nDotViewPosition=max(0.0,dot(newNormal,vp)); //求法向量vp的点积与0的最大值 diffuse=lightDiffuse*nDotViewPosition; //镜面光=材质反射系数 * 镜面光强度 * max(cos(入射角)粗糙度 ,0) float nDotViewHalfVector=dot(newNormal,halfVector); //点积(法线与半向量的点积) float powerFactor=max(0.0,pow(nDotViewHalfVector,shininess));//镜面光反射强度的因子 specular=lightSpecular*powerFactor; }