Threejs多重纹理与过程纹理实现

10 篇文章 2 订阅
10 篇文章 0 订阅

Threejs多重纹理与过程纹理实现

Threejs多重纹理与过程纹理实现

多数时候同一图元是采用单一纹理,但是为了增强显示效果,会存在同一图元多个纹理图的情况,效果比如只有灯光照射的时候才会显示其他图案,其他没有被照射到的地方显示正常灰色,边缘区域是平滑过渡的。这样就为图案的显隐更加增添一丝神秘气息,效果如下:
在这里插入图片描述
在这里插入图片描述
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

#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )
  SpotLight spotLight;
  #pragma unroll_loop
  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 );
    #ifdef USE_SHADOWMAP
    directLight.color *= all( bvec2( spotLight.shadow, directLight.visible ) ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;
    #endif
    RE_Direct( directLight, geometry, material, reflectedLight );
  }

#endif

光照计算函数:

…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桥梁,聚合团队。

本学习分享资料不得用于商业用途,仅做学习交流!!如有侵权立即删除!!


  • 微信公众号: BIM树洞
    在这里插入图片描述

  • 知乎专栏:BIM树洞

  • 气氛组博客:http://www.31bim.com

  • BIM应用及咨询,CAD,Revit, OpenGL,图形开发交流,加Q群1083064224

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值