three.js透光率实现原理归纳
.transmission : Float
透光率(或者说透光性),范围从0.0到1.0。默认值是0.0。
很薄的透明或者半透明的塑料、玻璃材质即便在几乎完全透明的情况下仍旧会保留反射的光线,透光性属性用于这种类型的材质。
当透光率不为0的时候, opacity透明度应设置为1.
会增加不少开销 额外渲染一次 单独渲染 作为
transmissionSamplerMap
传入
uniforms.transmissionSamplerMap.value = transmissionRenderTarget.texture;
function renderTransmissionPass( opaqueObjects, transmissiveObjects, scene, camera ) {
const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null;
if ( overrideMaterial !== null ) {
return;
}
if ( currentRenderState.state.transmissionRenderTarget[ camera.id ] === undefined ) {
currentRenderState.state.transmissionRenderTarget[ camera.id ] = new WebGLRenderTarget( 1, 1, {
generateMipmaps: true,
type: ( extensions.has( 'EXT_color_buffer_half_float' ) || extensions.has( 'EXT_color_buffer_float' ) ) ? HalfFloatType : UnsignedByteType,
minFilter: LinearMipmapLinearFilter,
samples: 4,
stencilBuffer: stencil,
resolveDepthBuffer: false,
resolveStencilBuffer: false,
colorSpace: ColorManagement.workingColorSpace,
} );
// debug
/*
const geometry = new PlaneGeometry();
const material = new MeshBasicMaterial( { map: _transmissionRenderTarget.texture } );
const mesh = new Mesh( geometry, material );
scene.add( mesh );
*/
}
const transmissionRenderTarget = currentRenderState.state.transmissionRenderTarget[ camera.id ];
const activeViewport = camera.viewport || _currentViewport;
transmissionRenderTarget.setSize( activeViewport.z, activeViewport.w );
//
const currentRenderTarget = _this.getRenderTarget();
_this.setRenderTarget( transmissionRenderTarget );
_this.getClearColor( _currentClearColor );
_currentClearAlpha = _this.getClearAlpha();
if ( _currentClearAlpha < 1 ) _this.setClearColor( 0xffffff, 0.5 );
_this.clear();
if ( _renderBackground ) background.render( scene );
// Turn off the features which can affect the frag color for opaque objects pass.
// Otherwise they are applied twice in opaque objects pass and transmission objects pass.
const currentToneMapping = _this.toneMapping;
_this.toneMapping = NoToneMapping;
// Remove viewport from camera to avoid nested render calls resetting viewport to it (e.g Reflector).
// Transmission render pass requires viewport to match the transmissionRenderTarget.
const currentCameraViewport = camera.viewport;
if ( camera.viewport !== undefined ) camera.viewport = undefined;
currentRenderState.setupLightsView( camera );
if ( _clippingEnabled === true ) clipping.setGlobalState( _this.clippingPlanes, camera );
renderObjects( opaqueObjects, scene, camera );
textures.updateMultisampleRenderTarget( transmissionRenderTarget );
textures.updateRenderTargetMipmap( transmissionRenderTarget );
if ( extensions.has( 'WEBGL_multisampled_render_to_texture' ) === false ) { // see #28131
let renderTargetNeedsUpdate = false;
for ( let i = 0, l = transmissiveObjects.length; i < l; i ++ ) {
const renderItem = transmissiveObjects[ i ];
const object = renderItem.object;
const geometry = renderItem.geometry;
const material = renderItem.material;
const group = renderItem.group;
if ( material.side === DoubleSide && object.layers.test( camera.layers ) ) {
const currentSide = material.side;
material.side = BackSide;
material.needsUpdate = true;
renderObject( object, scene, camera, geometry, material, group );
material.side = currentSide;
material.needsUpdate = true;
renderTargetNeedsUpdate = true;
}
}
if ( renderTargetNeedsUpdate === true ) {
textures.updateMultisampleRenderTarget( transmissionRenderTarget );
textures.updateRenderTargetMipmap( transmissionRenderTarget );
}
}
_this.setRenderTarget( currentRenderTarget );
_this.setClearColor( _currentClearColor, _currentClearAlpha );
if ( currentCameraViewport !== undefined ) camera.viewport = currentCameraViewport;
_this.toneMapping = currentToneMapping;
}
export default /* glsl */`
#ifdef USE_TRANSMISSION
material.transmission = transmission;
material.transmissionAlpha = 1.0;
material.thickness = thickness;
material.attenuationDistance = attenuationDistance;
material.attenuationColor = attenuationColor;
#ifdef USE_TRANSMISSIONMAP
material.transmission *= texture2D( transmissionMap, vTransmissionMapUv ).r;
#endif
#ifdef USE_THICKNESSMAP
material.thickness *= texture2D( thicknessMap, vThicknessMapUv ).g;
#endif
vec3 pos = vWorldPosition;
vec3 v = normalize( cameraPosition - pos );
vec3 n = inverseTransformDirection( normal, viewMatrix );
vec4 transmitted = getIBLVolumeRefraction(
n, v, material.roughness, material.diffuseColor, material.specularColor, material.specularF90,
pos, modelMatrix, viewMatrix, projectionMatrix, material.dispersion, material.ior, material.thickness,
material.attenuationColor, material.attenuationDistance );
material.transmissionAlpha = mix( material.transmissionAlpha, transmitted.a, material.transmission );
totalDiffuse = mix( totalDiffuse, transmitted.rgb, material.transmission );
#endif
`;