Blinn-Phong反射模型实践(web实现)
Blinn-Phong反射模型实践(web实现)
games101 第四次作业
最终完成带贴图的 Blinn-Phong 模型,产生光照效果
完成了
- 不带贴图的 Blinn-Phone 反射模型
- 带贴图的模型,但是纹理映射应用在顶点着色器上
- 带贴图的模型,纹理映射在片元着色器上
Blinn-Phone 光照模型
光照分为三种,分别为环境光,漫反射光和类镜面反射的高光。这分别对应三种反射,当光照射在物体表面,物体表面会发生相应的反射,将光反射到人眼当中,这样,人眼才能看见物体。
环境光简单理解为任何地方都有的一种光,光的颜色和强度相同,当然,现实可不是这样;漫反射在初中学过,在物体表面某个点发生漫反射后,从任何地方都能看到这个点且颜色强度都一样;高光反射类似光照到镜子上产生的高亮的效果。设置进入人眼的光为 L,漫反射为 Ld,高光反射为 Ls,环境反射为 La,可以有公式
L = L_a+L_d+Ls
\end{equation}
\]
环境反射
环境光由于任何地方的光照强度相同,因此有公式
\]
ka 代表了当前影响因子,可以令其为颜色,Ia 是光照强度,所有光照强度一致
该图是仅仅使用环境光和贴图产生的效果,Ia 设置为了 0.39,ka 设置为 vec3(1.0, 1.0, 1.0)。
漫反射
初中物理可以了解到,漫反射光强度一样,这里定义的漫反射光,从任何地方看向反射的点,强度都一样
由下图可以看到,I 表示原始光照强度,在三维空间中,光照强度以球面的形式向外扩散,因此强度衰减与球面积有关,假如光照与物体表面的点距离为 r,则在点处的光强为I/r^2
;光从正面照向一个物体和从侧面照向一个物体强度是不同的,从正面照强度最大,可以得到当前点应角度产生的影响为n*l
;如果 n*l
为负值,说明光在背面,无法被看到,因此有了下述图片展示的公式
Ld 表示漫反射强度,kd 表示影响因子,可以为颜色,I 为初始光照强度,r 为光源距离物体点的距离,n 为当前点的法向量,l 为点到光源的方向向量。将环境反射和漫反射加入程序中可得
单独和环境反射进行对比可以发现,牛牛变得更有轮廓了
高光反射
高光反射最为复杂,最重要的一点,当反射角与入射角大小一致时,光照强度最大。首先依下图所示定义多个变量,I 为点到光的方向向量,n 为点的法向量,v 为点到视角的方向向量。现在,我们知道,反射角与入射角一致时,强度最大,若此时反射角设为入射角大小,那么 v 与反射线的夹角越大,损失的光照越多,而 v 与反射线夹角可以转换为 n 与 h 的夹角。
h 叫半城向量,实际上就是 I 向量与 v 向量的角平分线的方向向量。此时因为 n 和 h 的夹角产生的光照损失值为 n * h
,其他部分与漫反射一致。I / r^2
表示光照随距离的缩减,ks 表示影响因子
将上述三种反射集合起来形成了 Blinn-Phone 反射模型,和前面两种对比,有了明显的高光
顶点着色器和片元着色器
在顶点着色器中,会遍历每个顶点的属性进行处理,此时的运算均是三角顶点的运算。WebGL 提供了 Shader 的加载,从顶点着色器中可以定义 vary
变量类型,并在片元着色器中接收
- 如果传输的是顶点坐标,那么在片元着色器中接收的是三角形内部像素点的顶点坐标
- 如果传输的是法向量,那么在片元着色器中接收到的是三角形内部经过插值后的法向量
- 如果传输的是顶点颜色,那么在片元着色器中接收到的是颜色插值
- 其他均如此,在片元着色器中会经过插值计算后产生逐像素的插值
逐顶点计算的反射代码
// 实现了自定义的颜色的 blinn-phong reflection
const vertexShader = `
// vec3 normal, uv,
varying vec3 vColor;
void main(){
// Ld 漫反射
vec3 lightPoint = vec3(3.0, 4.0, -3.0);
vec3 l = normalize(lightPoint - position);
float radius1 = distance(lightPoint, position);
// Kd
vec3 LdColor = vec3(1.0, 0.5, 0.7);
float Id = 1.0;
vec3 Ld = LdColor*(Id/radius1)*max(0.0, dot(normal,l));
// La 环境光
vec3 LaColor = vec3(1.0, 1.0, 1.0);
float Ia = 0.2;
// vec3 La = LaColor*Ia;
// 用自己的颜色
vec3 La = LdColor*Ia;
// Ls 镜面反射光
vec3 LsColor = vec3(1.0, 1.0, 1.0);
float Is =1.0;
vec3 vs = normalize(cameraPosition-position);
vec3 hs = normalize(vs+l);
float p = 30.0;
vec3 Ls = LsColor*(Is/radius1)* pow(max(0.0, dot(normal, hs)), p);
vColor = La + Ld + Ls;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`;
const fragmentShader = `
varying vec3 vColor;
void main(){
gl_FragColor = vec4(vColor, 1.0);
}
`;
逐片元计算的反射代码
//法线贴图
const vertexShader3 = `
// vec3 normal, uv,
varying vec3 vPosition;
varying vec3 vNormal;
varying vec2 vUv;
void main(){
vPosition = position;
vUv = uv;
vNormal = normal;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`;
//法线贴图处理
const fragmentShader3 = `
uniform sampler2D cowTexture;
uniform sampler2D cowNormalTexture;
varying vec3 vPosition;
varying vec3 vNormal;
varying vec2 vUv;
void main(){
vec4 map1 = texture2D(cowTexture, vUv);
vec3 selfColor = vec3(map1.x, map1.y, map1.z);
// 法线贴图将改变 normal
float uvAfterU = (vUv.x*1024.0+1.0)/1024.0;
float uvAfterV = (vUv.y*1024.0+1.0)/1024.0;
float c1 = 1.0;
float c2 = 1.0;
vec4 currentDepth = texture2D(cowNormalTexture, vUv);
vec4 currentDepthU = texture2D(cowNormalTexture, vec2(uvAfterU, vUv.y));
vec4 currentDepthV = texture2D(cowNormalTexture, vec2(vUv.x, uvAfterV));
// float dp_u = c1 *
if(uvAfterU<=1.0 && uvAfterV<=1.0){
}
// Ld 漫反射
vec3 lightPoint = vec3(3.0, 4.0, -3.0);
vec3 l = normalize(lightPoint - vPosition);
float radius1 = distance(lightPoint, vPosition);
// Kd
vec3 LdColor = vec3(1.0, 1.0, 1.0);
float Id = 1.0;
vec3 Ld = selfColor*(Id/radius1)*max(0.0, dot(vNormal,l));
//
// La 环境光
vec3 LaColor = vec3(1.0, 1.0, 1.0);
float Ia = 0.39;
// vec3 La = LaColor*Ia;
// 用自己的颜色
vec3 La = selfColor*Ia;
// Ls 镜面反射光
vec3 LsColor = vec3(1.0, 1.0, 1.0);
float Is =1.0;
vec3 vs = normalize(cameraPosition-vPosition);
vec3 hs = normalize(vs+l);
float p = 30.0;
vec3 Ls = selfColor*(Is/radius1)* pow(max(0.0, dot(vNormal, hs)), p);
// 整体颜色
vec3 vColor = La + Ld + Ls;
// vec3 vColor = La + Ld ;
// vec3 vColor = vec3(1.0, 0.6, 0.8);
gl_FragColor = vec4(vColor, 1.0);
}
`;
在之前的实践中采用了纯 CPU 的计算方式,原生 canvas API 渲染,但是效率和处理太慢,因此,后续的实验采用 threejs 框架加快实践效率
Blinn-Phong反射模型实践(web实现)的更多相关文章
- PBR Step by Step( 五)Phong反射模型
Lamertian模型描述了当光源直接照射到粗糙物体表面时,反射光线的分布情况.在现实中,除了直接光照,还有来自周围环境的间接光照. 直接照射到物体表面的光照,又称为局部光照: 间接照射到物体表面的光 ...
- 使用Actor模型管理Web Worker多线程
前端固有的编程思维是单线程,比如JavaScript语言的单线程.浏览器JS线程与UI线程互斥等等,Web Woker是HTML5新增的能力,为前端带来多线程能力.这篇文章简单记录一下搜狗地图WebG ...
- 用DirectX12实现Blinn Phong
这次我们来用DirectX12实现一下基本的Blinn Phong光照模型.让我们再把这个光照模型的概念过一遍:一个物体的颜色由三个因素决定:ambient, diffuse, specular.am ...
- Atitit..组件化事件化的编程模型--(2)---------Web datagridview 服务器端控件的实现原理and总结
Atitit..组件化事件化的编程模型--(2)---------Web datagridview 服务器端控件的实现原理and总结 1. 服务端table控件的几个流程周期 1 1.1. 确认要显示 ...
- JAVA进阶之旅(二)——认识Class类,反射的概念,Constructor,Field,Method,反射Main方法,数组的反射和实践
JAVA进阶之旅(二)--认识Class类,反射的概念,Constructor,Field,Method,反射Main方法,数组的反射和实践 我们继续聊JAVA,这次比较有意思,那就是反射了 一.认识 ...
- EJB_开发EJB容器模型的WEB服务
开发EJB容器模型的WEB服务 WEB服务 Web服务也是一种分布式技术,它与EJB最大的不同是,Web服务属于行业规范,可以跨平台及语言.而EJB属于Java平台的规范,尽管理论上可以跨平台,但实现 ...
- PBRT笔记(7)——反射模型
基础术语 表面反射可以分为4大类: diffuse 漫反射 glossy specular 镜面反射高光 perfect specular 完美反射高光 retro-reflective distri ...
- PBR Step by Step(四)Lambertian反射模型
光照可分为局部光照和全局光照. 局部光照:直接照射到物体表面的光照 全局光照:物体表面受周围环境影响的光照 左图中点x接收到周围环境的光线照射,来自周围表面的反射光照称为全局光照:右图中点x接收来自太 ...
- SNF快速开发平台2019-用户安全控制-权限管理模型实践-权限都在这里
1.1 是否保存密码 勾选记住密码后,再次开启程序用户密码不需要再次输入,直接显示在密码输入框内,方便快捷. 图 4.1‑1 记住密码的登录页面框 1.2 是否自动登录 勾选自动登录后,再 ...
随机推荐
- Python3元组的简介和遍历
一.Python3元组简介 1.1.如何创建一个元组 ''' Python的元组与列表类似,不同之处在于元组的元素不能修改. 元组使用小括号(),列表使用方括号[]. 元组创建很简单,只需要在括号中添 ...
- zabbix保姆级安装教程
安装步骤 1.进入官网选择下载的版本和服务器类型 官网地址:https://www.zabbix.com/cn/download?zabbix=5.0&os_distribution=cent ...
- libevent源码学习(10):min_heap数据结构解析
min_heap类型定义min_heap函数构造/析构函数及初始化判断event是否在堆顶判断两个event之间超时结构体的大小关系判断堆是否为空及堆大小返回堆顶event分配堆空间堆元素的上浮堆元素 ...
- Solon,一个轻量级的应用开发框架。发布官网喽!!!
官网发布: https://solon.noear.org/ 项目简介: Solon,是一个轻量级的应用开发框架.更快.更小.更自由! 支持JDK8+:主框架0.1Mb:组合不同的插件应对不同需求:方 ...
- AcWing1264. 动态求连续区间和 (树状数组做法)
1.题目 给定 n 个数组成的一个数列,规定有两种操作,一是修改某个元素,二是求子数列 [a,b] 的连续和. 输入格式 第一行包含两个整数 n 和 m,分别表示数的个数和操作次数. 第二行包含 n ...
- Apache Shiro使用官方自带的生成AES密钥
package test; import org.apache.shiro.codec.Base64; import javax.crypto.KeyGenerator; import javax.c ...
- SpringBoot 自定义注解
新增注解类 NotRepeatSubmit.java package com.example.demo.annotation; import java.lang.annotation.ElementT ...
- JAVA判断IP是否是内网IP
/** * 私有IP: * A类 10.0.0.0-10.255.255.255 * B类 172.16.0.0-172.31.255.255 * C类 192.168.0.0-192. ...
- 【LeetCode】669. Trim a Binary Search Tree 解题报告(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 递归 日期 题目地址:https://leetcod ...
- 【LeetCode】605. Can Place Flowers 解题报告(Python & C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 解题方法 贪婪算法 日期 题目地址:https://leetcode.c ...