Threejs多重纹理与过程纹理实现
Author--------------- Yen
多数时候同一图元是采用单一纹理,但是为了增强显示效果,会存在同一图元多个纹理图的情况,效果比如只有灯光照射的时候才会显示其他图案,其他没有被照射到的地方显示正常灰色,边缘区域是平滑过渡的。这样就为图案的显隐更加增添一丝神秘气息,效果如下:
1)对同一个图元采用多幅纹理图,这种技术称为多重纹理。
2)在多重纹理变化的边界根据某种规则进行平滑过渡效果,这种技术称为过程纹理。
这种平滑过渡在很多情况下都会用到,如有的时候白天黑夜不同图片的过渡,还有丘陵地形中根据不同海拔不同的纹理进行过渡。
具体实现核心代码如下:
自定义材质ShaderMaterial
var textureLoader = new THREE.TextureLoader();
// 需要增加的纹理贴图
var map = textureLoader.load( "textures/sprites/timg.jpg" );
// 自定义材质
var material = new THREE.ShaderMaterial({
uniforms: THREE.UniformsUtils.merge([
THREE.UniformsLib.common,
THREE.UniformsLib.specularmap,
THREE.UniformsLib.envmap,
THREE.UniformsLib.aomap,
THREE.UniformsLib.lightmap,
THREE.UniformsLib.emissivemap,
THREE.UniformsLib.bumpmap,
THREE.UniformsLib.normalmap,
THREE.UniformsLib.displacementmap,
THREE.UniformsLib.gradientmap,
THREE.UniformsLib.fog,
THREE.UniformsLib.lights,
{
emissive: { value: new THREE.Color( 0x000000 ) },
specular: { value: new THREE.Color( 0x111111 ) },
shininess: { value: 30 },
map: { value: undefined }
}
]),
vertexShader: THREE.ShaderChunk.meshphong_vert,
fragmentShader: THREE.ShaderChunk.meshphong_frag
});
material.lights = true;
material.uniforms.map.value = map;
var geometry = new THREE.PlaneBufferGeometry( 300, 200 );
var mesh = new THREE.Mesh( geometry, material );
其中比较重要的是修改THREE.ShaderChunk.meshphong_frag的源码(..src\renderers\shaders\ShaderLib\meshphong_frag.glsl.js),修改的核心代码:
// yen 增加的变量定义
varying vec2 vUv; // 记得对应的顶点着色器中也要增加UV
float vIntensity;
uniform sampler2D map;
......
// yen
vec4 mapColor = texture2D(map, vec2(vUv.x, vUv.y));
if (vIntensity > 0.21) {
// 光照强度大于0.21时候显示添加的纹理
gl_FragColor = vec4( vec3(mapColor.r, mapColor.g, mapColor.b), diffuseColor.a );
} else if (vIntensity < 0.05) {
// 相对较暗的地方显示之前纹理
gl_FragColor = vec4( outgoingLight, diffuseColor.a );
} else {
// 过渡区域按照百分比进行过渡
float t = (vIntensity - 0.05) / 0.16;
vec3 fragColor = t*vec3(mapColor.r, mapColor.g, mapColor.b) + (1.0-t) * outgoingLight;
gl_FragColor = vec4( fragColor, diffuseColor.a );
}
spotlight光照强度的计算
..src\renderers\shaders\ShaderChunk\lights_fragment_begin.glsl.js
SpotLight spotLight;
for ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {
spotLight = spotLights[ i ];
// getSpotDirectLightIrradiance( spotLight, geometry, directLight );
// 计算光照强度
vIntensity = getSpotDirectLightIntensity( spotLight, geometry, directLight);
getSpotDirectLightIrradiance( spotLight, geometry, directLight );
directLight.color *= all( bvec2( spotLight.shadow, directLight.visible ) ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;
RE_Direct( directLight, geometry, material, reflectedLight );
}
光照计算函数:
..src\renderers\shaders\ShaderChunk\lights_pars_begin.glsl.js
// yen 计算强度,参数是spotlight,还有方向光directLight
float getSpotDirectLightIntensity( const in SpotLight spotLight, const in GeometricContext geometry, in IncidentLight directLight ) {
float intensity = 0.0;
vec3 lVector = spotLight.position - geometry.position;
directLight.direction = normalize( lVector );
float lightDistance = length( lVector );
float angleCos = dot( directLight.direction, spotLight.direction );
if ( angleCos > spotLight.coneCos ) {
float spotEffect = smoothstep( spotLight.coneCos, spotLight.penumbraCos, angleCos );
intensity = spotEffect * punctualLightIntensityToIrradianceFactor( lightDistance, spotLight.distance, spotLight.decay );
}
return intensity;
}
这样就大功告成了。
参考文章:
OpenGL ES 3.x游戏开发 上卷 吴亚峰2016 Sample7_5
BIM树洞
做一个静谧的树洞君
用建筑的语言描述IT事物;
用IT的思维解决建筑问题;
共建BIM桥梁,聚合团队。
本学习分享资料不得用于商业用途,仅做学习交流!!如有侵权立即删除!!