<!-- SOLUV · part 116 -->
forms:Object}} shaderobject - The object holds the uniforms and the vertex and fragment shader source.
	 * @param {WebGLRenderer} renderer - A reference to the renderer.
	 */
	onBeforeCompile( /* shaderobject, renderer */ ) {}

	/**
	 * In case {@link Material#onBeforeCompile} is used, this callback can be used to identify
	 * values of settings used in `onBeforeCompile()`, so three.js can reuse a cached
	 * shader or recompile the shader for this material as needed.
	 *
	 * This method can only be used when rendering with {@link WebGLRenderer}.
	 *
	 * @return {string} The custom program cache key.
	 */
	customProgramCacheKey() {

		return this.onBeforeCompile.toString();

	}

	/**
	 * This method can be used to set default values from parameter objects.
	 * It is a generic implementation so it can be used with different types
	 * of materials.
	 *
	 * @param {Object} [values] - The material values to set.
	 */
	setValues( values ) {

		if ( values === undefined ) return;

		for ( const key in values ) {

			const newValue = values[ key ];

			if ( newValue === undefined ) {

				warn( `Material: parameter '${ key }' has value of undefined.` );
				continue;

			}

			const currentValue = this[ key ];

			if ( currentValue === undefined ) {

				warn( `Material: '${ key }' is not a property of THREE.${ this.type }.` );
				continue;

			}

			if ( currentValue && currentValue.isColor ) {

				currentValue.set( newValue );

			} else if (
				( ( currentValue && currentValue.isVector2 ) && ( newValue && newValue.isVector2 ) ) ||
				( ( currentValue && currentValue.isEuler ) && ( newValue && newValue.isEuler ) ) ||
				( ( currentValue && currentValue.isVector3 ) && ( newValue && newValue.isVector3 ) )
			) {

				currentValue.copy( newValue );

			} else {

				this[ key ] = newValue;

			}

		}

	}

	/**
	 * Serializes the material into JSON.
	 *
	 * @param {?(Object|string)} meta - An optional value holding meta information about the serialization.
	 * @return {Object} A JSON object representing the serialized material.
	 * @see {@link ObjectLoader#parse}
	 */
	toJSON( meta ) {

		const isRootObject = ( meta === undefined || typeof meta === 'string' );

		if ( isRootObject ) {

			meta = {
				textures: {},
				images: {}
			};

		}

		const data = {
			metadata: {
				version: 4.7,
				type: 'Material',
				generator: 'Material.toJSON'
			}
		};

		// standard Material serialization

		data.uuid = this.uuid;
		data.type = this.type;

		data.blending = this.blending;
		data.side = this.side;
		data.shadowSide = this.shadowSide;
		data.vertexColors = this.vertexColors;

		data.opacity = this.opacity;
		data.transparent = this.transparent;

		data.blendSrc = this.blendSrc;
		data.blendDst = this.blendDst;
		data.blendEquation = this.blendEquation;
		data.blendSrcAlpha = this.blendSrcAlpha;
		data.blendDstAlpha = this.blendDstAlpha;
		data.blendEquationAlpha = this.blendEquationAlpha;
		data.blendColor = this.blendColor.getHex();
		data.blendAlpha = this.blendAlpha;

		data.depthFunc = this.depthFunc;
		data.depthTest = this.depthTest;
		data.depthWrite = this.depthWrite;
		data.colorWrite = this.colorWrite;

		data.clipIntersection = this.clipIntersection;
		data.clipShadows = this.clipShadows;

		data.stencilWriteMask = this.stencilWriteMask;
		data.stencilFunc = this.stencilFunc;
		data.stencilRef = this.stencilRef;
		data.stencilFuncMask = this.stencilFuncMask;
		data.stencilFail = this.stencilFail;
		data.stencilZFail = this.stencilZFail;
		data.stencilZPass = this.stencilZPass;
		data.stencilWrite = this.stencilWrite;

		data.polygonOffset = this.polygonOffset;
		data.polygonOffsetFactor = this.polygonOffsetFactor;
		data.polygonOffsetUnits = this.polygonOffsetUnits;

		data.dithering = this.dithering;

		data.alphaTest = this.alphaTest;
		data.alphaHash = this.alphaHash;
		data.alphaToCoverage = this.alphaToCoverage;
		data.premultipliedAlpha = this.premultipliedAlpha;
		data.forceSinglePass = this.forceSinglePass;
		data.allowOverride = this.allowOverride;

		data.visible = this.visible;
		data.toneMapped = this.toneMapped;

		data.name = this.name;

		if ( this.color && this.color.isColor ) data.color = this.color.getHex();

		if ( this.roughness !== undefined ) data.roughness = this.roughness;
		if ( this.metalness !== undefined ) data.metalness = this.metalness;

		if ( this.sheen !== undefined ) data.sheen = this.sheen;
		if ( this.sheenColor && this.sheenColor.isColor ) data.sheenColor = this.sheenColor.getHex();
		if ( this.sheenRoughness !== undefined ) data.sheenRoughness = this.sheenRoughness;
		if ( this.emissive && this.emissive.isColor ) data.emissive = this.emissive.getHex();
		if ( this.emissiveIntensity !== undefined ) data.emissiveIntensity = this.emissiveIntensity;

		if ( this.specular && this.specular.isColor ) data.specular = this.specular.getHex();
		if ( this.specularIntensity !== undefined ) data.specularIntensity = this.specularIntensity;
		if ( th