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; // 记得对应的顶点着色器中也要增加UVfloat vIntensity;uniform sampler2D map;......// yenvec4 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,还有方向光directLightfloat 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桥梁,聚合团队。
本学习分享资料不得用于商业用途,仅做学习交流!!如有侵权立即删除!!
