Android OpenGLES3.0 开发 :光照基础
1.OpenGLES 基础光照模型
OpenGLES 目前还无法模拟现实世界的复杂光照效果,为了在效果要求和实现难度之间做一个平衡,往往采用一些简化的模型来模拟光照效果。冯氏光照模型(Phong Lighting Model)便是其中常用的一个光照模型,它由三种元素光组成,分别是:
- 环境光(Ambient Lighting)
- 散射光(Diffuse Lighting)
- 镜面光(Specular Lighting)。
2.环境光
环境光表示从四面八方照射到物体上且各个方向都均匀的光,不依赖于光源位置,没有方向性。
要把环境光照添加到场景里:光的颜色×很小常量环境因子×物体的颜色,然后使用它作为片段的颜色
float ambientStrength = 0.2; //环境光强度因子
ambient = ambientStrength * lightColor; //强度因子*光的颜色=环境光强度
3.散射光
散射光表示从物体表面向各个方向均匀反射的光。散射光的强度与入射光的强度及入射角密切相关,所以当光源位置发生变化,散射光效果也会发生明显变化。
散射光最终强度 = 材质反射系数 × 散射光强度 × max(cos(入射角),0)
其中入射角表示:当前片段光源照射方向与法向量之间的夹角。
float diffuseStrength = 0.6; //材质反射系数
vec3 unitNormal = normalize(vec3(u_ModelMatrix * vec4(a_normal, 1.0))); //对一个向量进行标准化
vec3 lightDir = normalize(lightPos - fragPos); //归一化 将光的位置-片元的位置 给归一化了
float diff = max(dot(unitNormal, lightDir), 0.0); //dot 电乘得到的是夹角
diffuse = diffuseStrength * diff * lightColor; //散射光强度
4.镜面光
镜面光是由光滑物体表面反射的方向比较集中的光,镜面光强度不仅依赖于入射光与法向量的夹角,也依赖于观察者的位置。
镜面光最终强度 = 材质镜面亮度因子 × 镜面光强度 × max(cos(反射光向量与视线方向向量夹角),0)
// Specular 镜面光 镜面光最终强度 = 材质镜面亮度因子 × 镜面光强度 × max(cos(反射光向量与视线方向向量夹角),0)
float specularStrength = 0.8; //材质镜面亮度因子
vec3 viewDir = normalize(viewPos - fragPos); // 将光的位置-片元的位置 给归一化了,得到一个三维向量
vec3 reflectDir = reflect(-lightDir, unitNormal); //光的折射向量
float spec = pow(max(dot(unitNormal, reflectDir), 0.0), 16.0); //前边值得16次方
specular = specularStrength * spec * lightColor;
v_texCoord = a_texCoord;
5.绘制一个自动旋转的立方体,旋转过程中光线不断在变化
void MSBasicLightSample::PaintGL() {glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);m_angle += 0.02f;glm::mat4 modelMat = glm::mat4(1.0f); //模型矩阵modelMat = glm::scale(modelMat, glm::vec3(0.8f, 0.8f, 0.8f));modelMat = glm::rotate(modelMat, m_angle, glm::vec3(1.0f, 0.0f, 0.0f));modelMat = glm::rotate(modelMat, m_angle, glm::vec3(0.0f, 1.0f, 0.0f));modelMat = glm::translate(modelMat, glm::vec3(0.0f, 0.0f, 0.0f));glm::mat4 projection =glm::perspective(glm::radians(60.0f), (float) 9 / (float) 18, 0.1f,1000.0f);// View matrixglm::mat4 ViewMat = glm::lookAt(glm::vec3(-3, 0, 3), // Camera is at (0,0,1), in World Spaceglm::vec3(0, 0, 0), // and looks at the originglm::vec3(0, 1, 0) // Head is up (set to 0,-1,0 to look upside-down));glm::mat4 mvpMatrix = projection * ViewMat * modelMat;m_pOpenGLShader->Bind();m_pOpenGLShader->SetUniformValue("u_MVPMatrix", mvpMatrix);m_pOpenGLShader->SetUniformValue("u_ModelMatrix", modelMat);m_pOpenGLShader->SetUniformValue("lightColor", glm::vec3(1.0f, 1.0f, 1.0f));m_pOpenGLShader->SetUniformValue("lightPos", glm::vec3(-2.0f, 0.0f, 2.0f));m_pOpenGLShader->SetUniformValue("viewPos", glm::vec3(-3.0f, 0.0f, 3.0f));m_pVAO->Bind();for (int i = 0; i < 6; i++) {glActiveTexture(GL_TEXTURE0);if (i==4){glBindTexture(GL_TEXTURE_2D, m_texID[i+1]);}else{glBindTexture(GL_TEXTURE_2D, m_texID[i]);}int offset = i * 6 * sizeof(unsigned short);glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (void *) offset);glBindTexture(GL_TEXTURE_2D, 0);}m_pOpenGLShader->Release();m_pVAO->Release();
}
- modelMat:模型矩阵用于控制旋转、缩放、平移等效果
- ViewMat:观察者矩阵,表示观察者的位置
- projection:透视矩阵区别于正交矩阵,透视矩阵有近大远小的视觉效果,正交矩阵则没有。
将MVP矩阵、模型矩阵、光的位置、光的颜色与观察者的位置传给shader。
顶点着色器
#version 300 es
precision mediump float;
layout(location = 0) in vec4 a_position;
layout(location = 1) in vec2 a_texCoord;
layout(location = 2) in vec3 a_normal;uniform mat4 u_MVPMatrix; //MVP矩阵
uniform mat4 u_ModelMatrix; //模型矩阵
uniform vec3 lightPos; //光的位置
uniform vec3 lightColor; //光的颜色
uniform vec3 viewPos; //观察者的位置
out vec2 v_texCoord; //输出的材质
out vec3 ambient; //环境光
out vec3 diffuse; //散射光
out vec3 specular; //镜面光void main() {gl_Position = u_MVPMatrix * a_position; //投影变换之后,输出的是gl_Position,也就是说你最终画在屏幕里面的哪个位置vec3 fragPos = vec3(u_ModelMatrix * a_position); //当前片元坐标:也就是通过旋转等变换之后的坐标// Ambient 环境光 要把环境光照添加到场景里,只需用光的颜色乘以一个(数值)很小常量环境因子,再乘以物体的颜色,然后使用它作为片段的颜色float ambientStrength = 0.2; //环境光强度因子ambient = ambientStrength * lightColor; //强度因子*光的颜色=环境光强度// Diffuse 散射光 散射光最终强度 = 材质反射系数 × 散射光强度 × max(cos(入射角),0)float diffuseStrength = 0.6; //材质反射系数vec3 unitNormal = normalize(vec3(u_ModelMatrix * vec4(a_normal, 1.0))); //对一个向量进行标准化vec3 lightDir = normalize(lightPos - fragPos); //归一化 将光的位置-片元的位置 给归一化了,得到一个三维向量float diff = max(dot(unitNormal, lightDir), 0.0); //dot 电乘得到的是夹角diffuse = diffuseStrength * diff * lightColor; //散射光强度// Specular 镜面光 镜面光最终强度 = 材质镜面亮度因子 × 镜面光强度 × max(cos(反射光向量与视线方向向量夹角),0)float specularStrength = 0.8; //材质镜面亮度因子vec3 viewDir = normalize(viewPos - fragPos); // 将光的位置-片元的位置 给归一化了,得到一个三维向量vec3 reflectDir = reflect(-lightDir, unitNormal); //光的折射向量float spec = pow(max(dot(unitNormal, reflectDir), 0.0), 16.0); //前边值得16次方specular = specularStrength * spec * lightColor;v_texCoord = a_texCoord;}
顶点着色器根据传入的光的数据以及位置信息计算光线的强度,注释写的比较清楚。
片元着色器
#version 300 es
precision mediump float;in vec2 v_texCoord;
in vec3 ambient;
in vec3 diffuse;
in vec3 specular;
layout(location = 0) out vec4 outColor;
uniform sampler2D s_TextureMap;void main() {vec4 objectColor = texture(s_TextureMap, v_texCoord);vec3 finalColor = (ambient + diffuse + specular) * vec3(objectColor);outColor = vec4(finalColor, 1.0); //增加A 通道
}
片元着色器:将顶点着色器计算的光线直接跟采样器得到的颜色相乘得到了最终的颜色
Android OpenGLES3.0 开发 :光照基础相关推荐
- Android 音视频开发之基础篇 使用 SurfaceView绘制一张图片
Android 音视频开发 上一篇文章:使用 imageview绘制一张图片 任务一 SurfaceView绘制一张图片 文章目录 Android 音视频开发 前言 一.surfaceview是什么? ...
- Android Studio学习开发笔记--基础
关于进阶项目篇,点击这里 文章目录 前言 构建首个应用 运行 第一次可能会出现的问题 想要重新下载安装Android Studio 文件在哪里编辑 android基础--控件 基础属性 带阴影的Tex ...
- Android Studio(0)开发开篇 环境搭建 创建工程 2020.3.1版本 虚拟手机
系列文章目录 文章目录 系列文章目录 前言 一.Android Studio简介 二.安装并创建新项目 1.Hello Android 前言 近期因公司开发的项目需要开发手机APP,所以开始学习And ...
- Android 音视频开发之基础篇 使用 imageview绘制一张图片
Android 音视频开发 任务一 ImageView 绘制图片 文章目录 Android 音视频开发 任务一 ImageView 绘制图片 前言 一.配置activity_main.xml 二.添加 ...
- Ubuntu11 10 64Bit版上的Android 4 0 开发环境搭建
据说Android以后新版本只支持64bit版本开发,所以搭建一个64bit系统的Android开发环境为将来的Android4.0 及更高版本 开发打好基础. 一.准备工作 1.1 硬件 PC 一台 ...
- 2019零基础学Android第0课——零基础怎么学Android?
按照正常逻辑,今天应该是直接进入AndroidStudio开发环境搭建课程了.但我想在写这系列之前,先和一些刚入门的同学一起来探讨下,怎么去学习Android? 当今社会大家应该都会有个感受:信息实在 ...
- android 地图导航开发思路,基础功能-导航组件-开发指南-Android 导航SDK | 高德地图API...
预置条件 请在您工程的 AndroidManifest.xml 中配置声明导航组件 Activity: android:name="com.amap.api.navi.AmapRouteAc ...
- android 6.0 开发板 adb shell 使用 sqlite3
没有root 或者 没有 system 文件夹写权限的,可以不用往下看了. 网上的adb shell 添加 sqlite3的方法大多已经过时. 目前方法经实际验证可行. 主要是三个文件 : https ...
- 使用BleLib的轻松搞定Android低功耗蓝牙Ble 4.0开发详解
转载请注明来源: http://blog.csdn.net/kjunchen/article/details/50909410 使用BleLib的轻松搞定Android低功耗蓝牙Ble 4.0开发详解 ...
最新文章
- 2022年十大AI预测
- 是啥意思_属猴人:十猴九苦是啥意思 十猴九不全什么意思 为什么
- xml方式实现aop-快速入门
- python面向对象三大特性、类的约束、print带颜色输出及super补充
- C# System.Windows.Forms.NumericUpDown 控件全选其中文字
- 手写table用ajax遍历,原生js把数据循遍历到前端table
- cisco 华三 对接_Cisco ACS 5.6与华为,H3C设备对接操作指引
- 变态的儿童国学教育与孔子真正的教育之道
- Java对象序列化文件追加对象的问题,以及Java的读取多个对象的问题解决方法。
- Javascript特效:普通轮播图
- EXCEL表格中数字金额很大时后面零很多,如何设置直接以万元为单位显示,不显示后面的零
- vue实现:带关键字跳转企查查并搜索关键字对应的企业
- [攻防世界]crypto新手练习区Caesar
- 将你的现实生活照片变成卡通头像
- tensorflow的None下标、equal和consum函数总结
- 【Microsoft Azure 的1024种玩法】十五.通过Web浏览器对Auzre VM 服务器运维管理
- 多边形等距放缩原理与python实现
- 动态刷新listview数据
- python----模块和包
- 关键信息基础设施保护条例_五个图表:读懂网络安全等级保护制度与关键信息基础设施保护制度...
热门文章
- 机器人领域相关英文期刊
- 谷歌翻译网页无法翻译,最新解决方法
- ABP开发框架前后端开发系列---(8)ABP框架之Winform界面的开发过程
- 第四十六章 Caché 变量大全 ^$GLOBAL 变量
- 【洛谷P3258】松鼠的新家
- java实现第七届蓝桥杯交换瓶子
- TCP协议网络安全攻击
- MyBatis 入门 (二级缓存脏读)
- word表格和后面的文字间距太小
- 一个海底隧道中只有一个车道,规定同一个方向的可以连续过隧道。某方向有列车过隧道时,另一个方向的列车就要等待, 现在东岸和西岸都有列车要过隧道,如果把每个过隧道的列车看作一个进程,使用P、V操作