Lensflare.create constructor
Lensflare.create(
- BufferGeometry? geometry,
- Material? material
Implementation
Lensflare.create(super.geometry,super.material){
type = 'Lensflare';
frustumCulled = false;
renderOrder = double.maxFinite.toInt();
final positionScreen = Vector3();
final positionView = Vector3();
// textures
final tempMap = FramebufferTexture( 16, 16 );
final occlusionMap = FramebufferTexture( 16, 16 );
int currentType = UnsignedByteType;
// material
final geometry = Lensflare.Geometry;
final material1a = RawShaderMaterial.fromMap( {
'uniforms': {
'scale': <String,dynamic>{ 'value': null },
'screenPosition': <String,dynamic>{ 'value': null }
},
'vertexShader': /* glsl */'''
${!kIsWeb && Platform.isLinux ?'':'precision highp float'};
uniform vec3 screenPosition;
uniform vec2 scale;
attribute vec3 position;
void main() {
gl_Position = vec4( position.xy * scale + screenPosition.xy, screenPosition.z, 1.0 );
}''',
'fragmentShader': /* glsl */'''
${!kIsWeb && Platform.isLinux ?'':'precision highp float'};
void main() {
gl_FragColor = vec4( 1.0, 0.0, 1.0, 1.0 );
}''',
'depthTest': true,
'depthWrite': false,
'transparent': false
} );
final material1b = RawShaderMaterial.fromMap( {
'uniforms': {
'map': <String,dynamic>{ 'value': tempMap },
'scale': <String,dynamic>{ 'value': null },
'screenPosition': <String,dynamic>{ 'value': null }
},
'vertexShader': /* glsl */'''
${!kIsWeb && Platform.isLinux ?'':'precision highp float'};
uniform vec3 screenPosition;
uniform vec2 scale;
attribute vec3 position;
attribute vec2 uv;
varying vec2 vUV;
void main() {
vUV = uv;
gl_Position = vec4( position.xy * scale + screenPosition.xy, screenPosition.z, 1.0 );
}''',
'fragmentShader': /* glsl */'''
${!kIsWeb && Platform.isLinux ?'':'precision highp float'};
uniform sampler2D map;
varying vec2 vUV;
void main() {
gl_FragColor = texture2D( map, vUV );
}''',
'depthTest': false,
'depthWrite': false,
'transparent': false
} );
// the following object is used for occlusionMap generation
final mesh1 = Mesh( geometry, material1a );
//
final List elements = [];
final shader = LensflareElement.shader;
final material2 = RawShaderMaterial.fromMap( {
'name': shader['name'],
'uniforms': {
'map': <String,dynamic>{ 'value': null },
'occlusionMap': <String,dynamic>{ 'value': occlusionMap },
'color': <String,dynamic>{ 'value': Color.fromHex32( 0xffffff ) },
'scale': <String,dynamic>{ 'value': Vector2() },
'screenPosition': <String,dynamic>{ 'value': Vector3() }
},
'vertexShader': shader['vertexShader'],
'fragmentShader': shader['fragmentShader'],
'blending': AdditiveBlending,
'transparent': true,
'depthWrite': false
} );
final mesh2 = Mesh( geometry, material2 );
addElement = ( element ) {
elements.add( element );
};
//
final scale = Vector2();
final screenPositionPixels = Vector2();
final validArea = BoundingBox();
final viewport = Vector4();
onBeforeRender = ({
WebGLRenderer? renderer,
RenderTarget? renderTarget,
Object3D? mesh,
Scene? scene,
Camera? camera,
BufferGeometry? geometry,
Material? material,
Map<String, dynamic>? group
}) {
renderer?.getCurrentViewport( viewport );
final renderTarget = renderer!.getRenderTarget();
final type = ( renderTarget != null ) ? renderTarget.texture.type : UnsignedByteType;
if ( currentType != type ) {
tempMap.dispose();
occlusionMap.dispose();
tempMap.type = occlusionMap.type = type;
currentType = type;
}
final invAspect = viewport.w / viewport.z;
final halfViewportWidth = viewport.z / 2.0;
final halfViewportHeight = viewport.w / 2.0;
double size = 16 / viewport.w;
scale.setValues( size * invAspect, size );
validArea.min.setValues( viewport.x, viewport.y );
validArea.max.setValues( viewport.x + ( viewport.z - 16 ), viewport.y + ( viewport.w - 16 ) );
// calculate position in screen space
positionView.setFromMatrixPosition(matrixWorld );
positionView.applyMatrix4( camera!.matrixWorldInverse );
if ( positionView.z > 0 ) return; // lensflare is behind the camera
positionScreen.setFrom( positionView ).applyMatrix4( camera.projectionMatrix );
// horizontal and vertical coordinate of the lower left corner of the pixels to copy
screenPositionPixels.x = viewport.x + ( positionScreen.x * halfViewportWidth ) + halfViewportWidth - 8;
screenPositionPixels.y = viewport.y + ( positionScreen.y * halfViewportHeight ) + halfViewportHeight - 8;
// screen cull
if ( validArea.containsPoint(screenPositionPixels ) ) {
// save current RGB to temp texture
renderer.copyFramebufferToTexture( screenPositionPixels, tempMap );
// render pink quad
Map<String, dynamic> uniforms = material1a.uniforms;
uniforms['scale'] = <String, dynamic>{'value' : scale};
uniforms['screenPosition'] = <String, dynamic>{'value': positionScreen};
renderer.renderBufferDirect( camera, null, geometry!, material1a, mesh1, null );
// copy result to occlusionMap
renderer.copyFramebufferToTexture( screenPositionPixels, occlusionMap );
// restore graphics
uniforms = material1b.uniforms;
uniforms['scale'] = <String, dynamic>{'value' : scale};
uniforms['screenPosition'] = <String, dynamic>{'value': positionScreen};
//renderer.renderBufferDirect( camera, null, geometry, material1b, mesh1, null );
// render elements
final vecX = - positionScreen.x * 2;
final vecY = - positionScreen.y * 2;
for (int i = 0, l = elements.length; i < l; i ++ ) {
final element = elements[i];
final uniforms = material2.uniforms;
uniforms[ 'color' ]['value'].setFrom( element.color );
uniforms[ 'map' ]['value'] = element.texture;
uniforms[ 'screenPosition' ]['value'].x = positionScreen.x + vecX * element.distance;
uniforms[ 'screenPosition' ]['value'].y = positionScreen.y + vecY * element.distance;
size = element.size / viewport.w;
final invAspect = viewport.w / viewport.z;
uniforms[ 'scale' ]['value'].setValues( size * invAspect, size );
material2.uniformsNeedUpdate = true;
renderer.renderBufferDirect( camera, null, geometry, material2, mesh2, null );
}
}
};
dispose1 = () {
material1a.dispose();
material1b.dispose();
material2.dispose();
tempMap.dispose();
occlusionMap.dispose();
for (int i = 0, l = elements.length; i < l; i ++ ) {
elements[i].texture.dispose();
}
};
}