three.js常用材质:基本材质兰伯特材质冯氏材质标准材质

我们可以自己使用着色器实现这些材质,用于批量渲染等用途。

为了简单,假设物体只有一张漫反射贴图,场景中只存在一个环境光和一个平行光。

一、基本材质(MeshBasicMaterial)

基本材质不对光源产生反应。

顶点着色器

varying vec2 vUv;

void main() {
vUv = uv; vec3 transformed = vec3( position );
vec4 mvPosition = modelViewMatrix * vec4( transformed, 1.0 );
gl_Position = projectionMatrix * mvPosition;
}

片源着色器

uniform vec3 diffuse;
uniform float opacity; uniform sampler2D map; varying vec2 vUv; void main() {
vec4 diffuseColor = vec4( diffuse, opacity ); vec4 texelColor = texture2D( map, vUv );
diffuseColor *= texelColor; gl_FragColor = diffuseColor;
}

二、兰伯特材质(MeshLambertMaterial)

兰伯特材质只有漫反射,没有高光。

顶点着色器

uniform vec3 directColor; // 平行光颜色
uniform vec3 directDirection; // 平行光方向 #define PI 3.14159265359 varying vec2 vUv;
varying vec3 vLightFront; void main() {
vUv = uv; vec3 transformedNormal = normalMatrix * vec3( normal ); vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
gl_Position = projectionMatrix * mvPosition; float dotNL = dot( normalize( transformedNormal ), directDirection );
vLightFront = clamp( dotNL, 0.0, 1.0 ) * PI * directColor;
}

片源着色器

uniform vec3 diffuse; // 物体颜色
uniform float opacity; // 透明度 uniform sampler2D map; uniform vec3 ambientColor; // 漫反射光颜色 varying vec2 vUv;
varying vec3 vLightFront; // 双向反射PI
#define RECIPROCAL_PI 0.31830988618 void main() {
vec4 diffuseColor = vec4( diffuse, opacity ); vec4 texelColor = texture2D( map, vUv );
diffuseColor *= texelColor; // 出射光 = 直接漫反射 + 间接漫反射
vec3 outgoingLight = vLightFront + ambientColor * RECIPROCAL_PI * diffuseColor.rgb; gl_FragColor = vec4( outgoingLight, diffuseColor.a );
}

三、冯氏材质(MeshPhongMaterial)

冯氏材质很重要的两个属性是高光颜色(specular)光亮度(shininess)

顶点着色器

varying vec2 vUv;
varying vec3 vNormal;
varying vec3 vViewPosition; void main() {
vUv = uv;
vNormal = normalize( normalMatrix * normal ); vec3 transformed = vec3( position );
vec4 mvPosition = modelViewMatrix * vec4( transformed, 1.0 );
vViewPosition = - mvPosition.xyz; gl_Position = projectionMatrix * mvPosition;
}

片源着色器

// 参考资料:
// BRDF-双向反射分布函数:https://baike.baidu.com/item/双向反射分布函数/22311036
// 常见的三个光照模型:Lambert,Phong,BlinnPhong:https://blog.csdn.net/taoqilin/article/details/52800702
// 菲涅尔公式:https://baike.baidu.com/item/菲涅耳公式/9103788
// 菲涅尔折射率:https://baike.baidu.com/item/菲涅尔折射率/2712906 uniform vec3 diffuse; // 物体颜色
uniform float opacity; // 透明度
uniform vec3 specular; // 高光颜色
uniform float shininess; // 光亮度 uniform sampler2D map; uniform vec3 ambientColor; // 漫反射光颜色
uniform vec3 directColor; // 平行光颜色
uniform vec3 directDirection; // 平行光方向 varying vec2 vUv;
varying vec3 vNormal;
varying vec3 vViewPosition; // 双向反射PI
#define RECIPROCAL_PI 0.31830988618 // 菲涅尔反射
vec3 F_Schlick( const in vec3 specularColor, const in float dotLH ) {
float fresnel = exp2( ( -5.55473 * dotLH - 6.98316 ) * dotLH );
return ( 1.0 - specularColor ) * fresnel + specularColor;
} // Blinn-Phong光照模型
float D_BlinnPhong( const in float shininess, const in float dotNH ) {
return RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );
} void main() {
// 物体颜色
vec4 diffuseColor = vec4( diffuse, opacity ); vec4 texelColor = texture2D( map, vUv );
diffuseColor *= texelColor; // 环境光漫反射(BRDF兰伯特漫反射)
vec3 indirectDiffuse = ambientColor * RECIPROCAL_PI * diffuseColor.rgb; // 法线
vec3 normal = normalize( vNormal ); // 平行光漫反射(BRDF兰伯特漫反射)
float dotNL = clamp( dot( normal, directDirection ), 0.0, 1.0 );
vec3 irradiance = dotNL * directColor;
vec3 directDiffuse = irradiance * RECIPROCAL_PI * diffuseColor.rgb; // 平行光镜面反射
vec3 halfDir = normalize( directDirection + normalize( vViewPosition ) ); // 半角向量
float dotNH = clamp( dot( normal, halfDir ), 0.0, 1.0 );
float dotLH = clamp( dot( directDirection, halfDir ), 0.0, 1.0 );
vec3 F = F_Schlick( specular, dotLH ); // 菲涅尔反射
float D = D_BlinnPhong( shininess, dotNH ); // Blinn-Phong光照模型
vec3 directSpecular = F * ( 0.25 * D ); // 出射光 = 环境光漫反射 + 平行光漫反射 + 平行光镜面反射
vec3 outgoingLight = indirectDiffuse + directDiffuse + directSpecular; gl_FragColor = vec4( outgoingLight, diffuseColor.a );
}

四、标准材质(MeshStandardMaterial)

标准材质也叫物理材质或pbr材质,很重要的两个属性是金属度(metalness)粗糙度(roughness)

顶点着色器

varying vec2 vUv;
varying vec3 vNormal;
varying vec3 vViewPosition; void main() {
vUv = uv;
vNormal = normalize( normalMatrix * vec3( normal ) ); vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
vViewPosition = - mvPosition.xyz; gl_Position = projectionMatrix * mvPosition;
}

片源着色器

// 参考资料:
// BRDF-双向反射分布函数:https://baike.baidu.com/item/双向反射分布函数/22311036
// 基于物理的渲染—更精确的微表面分布函数GGX: https://www.jianshu.com/p/be4f025aeb3c
// 菲涅尔公式:https://baike.baidu.com/item/菲涅耳公式/9103788
// 菲涅尔折射率:https://baike.baidu.com/item/菲涅尔折射率/2712906
// Moving Frostbite to Physically Based Rendering 3.0: https://blog.csdn.net/wodownload2/article/details/103126247 uniform vec3 diffuse; // 物体颜色
uniform float opacity; // 透明度
uniform float metalness; // 金属度
uniform float roughness; // 粗糙度 uniform sampler2D map; uniform vec3 ambientColor; // 漫反射光颜色
uniform vec3 directColor; // 平行光颜色
uniform vec3 directDirection; // 平行光方向 varying vec2 vUv;
varying vec3 vNormal;
varying vec3 vViewPosition; // 双向反射PI
#define RECIPROCAL_PI 0.31830988618 // 菲涅尔反射
vec3 F_Schlick( const in vec3 specularColor, const in float dotLH ) {
float fresnel = exp2( ( -5.55473 * dotLH - 6.98316 ) * dotLH );
return ( 1.0 - specularColor ) * fresnel + specularColor;
} float G_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {
float a2 = pow2( alpha );
float gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );
float gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );
return 0.5 / max( gv + gl, EPSILON );
} // 微表面分布函数
float D_GGX( const in float alpha, const in float dotNH ) {
float a2 = pow2( alpha );
float denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;
return RECIPROCAL_PI * a2 / pow2( denom );
} vec3 BRDF_Specular_GGX( const in vec3 directDirection, const in vec3 normal, const in viewDir, const in vec3 specularColor, const in float roughness ) {
float alpha = pow2( roughness );
vec3 halfDir = normalize( directDirection + viewDir );
float dotNL = clamp( dot( normal, directDirection ), 0.0, 1.0 );
float dotNV = clamp( dot( normal, viewDir ), 0.0, 1.0 );
float dotNH = clamp( dot( normal, halfDir ), 0.0, 1.0 );
float dotLH = clamp( dot( directDirection, halfDir ), 0.0, 1.0 );
vec3 F = F_Schlick( specularColor, dotLH );
float G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV );
float D = D_GGX( alpha, dotNH );
return F * ( G * D );
} void main() {
vec4 diffuseColor = vec4( diffuse, opacity ); vec4 texelColor = texture2D( map, vUv );
diffuseColor *= texelColor; // 法线
vec3 normal = normalize( vNormal ); // 环境光
vec3 indirectDiffuse = ambientColor * RECIPROCAL_PI * diffuseColor.rgb * ( 1.0 - metalness ); // 间接漫反射 // 平行光
float dotNL = clamp( dot( normal, directDirection ), 0.0, 1.0 );
vec3 irradiance = dotNL * directColor;
vec3 specularColor = mix( vec3( 0.04 ), diffuseColor.rgb, metalness ); vec3 directDiffuse = irradiance * RECIPROCAL_PI * diffuseColor.rgb * ( 1.0 - metalness ); // 直接漫反射
vec3 directSpecular = irradiance * BRDF_Specular_GGX( directDirection, normal, normalize( vViewPosition ), specularColor, clamp( roughness, 0.04, 1.0 ) ); // 直接镜面反射 // 出射光 = 间接漫反射光 + 直接漫反射 + 直接镜面反射光
vec3 outgoingLight = indirectDiffuse + directDiffuse + directSpecular; gl_FragColor = vec4( outgoingLight, diffuseColor.a );
}

四种材质完整实现源码:https://gitee.com/tengge1/ShadowEditor/tree/master/ShadowEditor.Web/src/render/shader/material_simple

参考资料

1. 基于three.js的开源三维场景编辑器https://github.com/tengge1/ShadowEditor
7. Moving Frostbite to Physically Based Rendering 3.0: https://blog.csdn.net/wodownload2/article/details/103126247
 

three.js各种材质的实现源码的更多相关文章

  1. JS魔法堂:jsDeferred源码剖析

    一.前言 最近在研究Promises/A+规范及实现,而Promise/A+规范的制定则很大程度地参考了由日本geek cho45发起的jsDeferred项目(<JavaScript框架设计& ...

  2. 原生JS研究:学习jquery源码,收集整理常用JS函数

    原生JS研究:学习jquery源码,收集整理常用JS函数: 1. JS获取原生class(getElementsByClass) 转自:http://blog.csdn.net/kongjiea/ar ...

  3. 如何优雅的阅读 GitHub 上开源 js 框架和库的源码

    如何优雅的阅读 GitHub 上开源 js 框架和库的源码 step 先总后分,即先了解一下啊框架的大体架构,又一个全局的认识,在选择某些和感兴趣的部分,仔细阅读,各个击破: 带着问题阅读,用到了什么 ...

  4. jquery自定义插件结合baiduTemplate.js实现异步刷新(附源码)

    上一篇记录了BaiduTemplate模板引擎使用示例附源码,在此基础上对使用方法进行了封装 自定义插件jajaxrefresh.js 代码如下: //闭包限定命名空间 (function ($) { ...

  5. JS魔法堂:剖析源码理解Promises/A规范

    一.前言 Promises/A是由CommonJS组织制定的异步模式编程规范,有不少库已根据该规范及后来经改进的Promises/A+规范提供了实现 如Q, Bluebird, when, rsvp. ...

  6. JS魔法堂:mmDeferred源码剖析

    一.前言 avalon.js的影响力愈发强劲,而作为子模块之一的mmDeferred必然成为异步调用模式学习之旅的又一站呢!本文将记录我对mmDeferred的认识,若有纰漏请各位指正,谢谢.项目请见 ...

  7. 百度地图 api 功能封装类 (ZMap.js) 本地搜索,范围查找实例 [源码下载]

    相关说明 1. 界面查看: 吐槽贴:百度地图 api 封装 的实用功能 [源码下载] 2. 功能说明: 百度地图整合功能分享修正版[ZMap.js] 实例源码! ZMap.js 本类方法功能大多使用 ...

  8. 百度地图 api 功能封装类 (ZMap.js) 新增管理事件功能 [源码下载]

    ZMap 功能说明 ZMap.js 本类方法功能大多使用 prototype 原型 实现: 包含的功能有:轨迹回放,圈画区域可编辑,判断几个坐标是否在一个圆圈内,生活服务查询,从经纬度获取地址信息,地 ...

  9. 【 js 性能优化】【源码学习】underscore throttle 与 debounce 节流

    在看 underscore.js 源码的时候,接触到了这样两个方法,很有意思: 我先把实现的代码撂在下面,看不懂的可以先跳过,但是跳过可不是永远跳过哦- 一个是 throttle: _.throttl ...

随机推荐

  1. python——直接插入排序

    直接插入排序 直接插入排序原理 直接插入排序过程 代码 时间复杂度分析 排序稳定性

  2. TRANK和VTP

    需求:因为公司规模逐渐扩大,出现相同部门不同办公室的情况,老板提出新的要求:相同部门可以通信,不同部门不能通信. 利用vlan: 缺点:浪费材料,应用技术手段把两条交叉线变成一条. 因此,引进trun ...

  3. Asciinema:你的所有操作都将被录制

    如何实现类似于Jumpserver koko一样的终端录制回放功能呢?本文介绍一个神器 asciinema 是一款开源免费的终端录制工具,它可以将命令行输入输出的任何内容加上时间保存在文件中,同时还提 ...

  4. IDEA中WEB项目本地调试和发布的配置分开配置

    一个Web项目,开发的时候设置了一些本地内容,比如IP地址,还有本地目录等.开发完成后,要发布到服务器上时,这些本地相关的配置,就需要配置成服务器上IP或目录. 原先的做法就是部署打包的时候,把相关的 ...

  5. PHP 面试踩过的坑

    1.get,post 的区别 **显示有区别 ** get方法是将字符串拼接在地址栏后面可以看见 而post方法看不见 **传递的大小有区别 ** 具体大小和浏览器有关系,ie浏览器是2k其他浏览器的 ...

  6. CCF-画字符-详细的注释

    import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.i ...

  7. 学习完vue指令 做的一个学生信息录入系统

    一.demo实现原理 输入完个人信息后  点击创建用户  数据就会显示在下面的表格中 用到了vue中的数据双向绑定 v-model v-for 还要js正则 数组的unshift splice 等方法 ...

  8. NTP服务搭建详解一条龙

    说在前面:ntp和ntpdate区别 ①两个服务都是centos自带的(centos7中不自带ntp).ntp的安装包名是ntp,ntpdate的安装包是ntpdate.他们并非由一个安装包提供. ② ...

  9. C#学习笔记05--枚举/结构体

    一.枚举   当变量的取值范围是固定的几个时, 就可以使用枚举类型, 这样会更加简洁方便   1.1.定义: 访问修饰符 enum 枚举类型名 { 成员1, 成员2, 成员3, ... } publi ...

  10. CTF比赛时准备的一些shell命令

    防御策略: sudo service apache2 start :set fileformat=unix1.写脚本关闭大部分服务,除了ssh       2.改root密码,禁用除了root之外的所 ...