Threejs 材质webgl源码

本文深入解析了Three.js中的四种常用材质:基本材质、兰伯特材质、冯氏材质及标准材质,并提供了每种材质的顶点着色器与片元着色器的源码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • Threejs 材质webgl源码**

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.youkuaiyun.com/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.youkuaiyun.com/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 );

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值