81 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			81 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
|  | import TempNode from '../core/TempNode.js'; | ||
|  | import { addNodeClass } from '../core/Node.js'; | ||
|  | import { uv } from '../accessors/UVNode.js'; | ||
|  | import { normalView } from '../accessors/NormalNode.js'; | ||
|  | import { positionView } from '../accessors/PositionNode.js'; | ||
|  | import { faceDirection } from './FrontFacingNode.js'; | ||
|  | import { addNodeElement, tslFn, nodeProxy, float, vec2 } from '../shadernode/ShaderNode.js'; | ||
|  | 
 | ||
|  | // Bump Mapping Unparametrized Surfaces on the GPU by Morten S. Mikkelsen
 | ||
|  | // https://mmikk.github.io/papers3d/mm_sfgrad_bump.pdf
 | ||
|  | 
 | ||
|  | const dHdxy_fwd = tslFn( ( { textureNode, bumpScale } ) => { | ||
|  | 
 | ||
|  | 	// It's used to preserve the same TextureNode instance
 | ||
|  | 	const sampleTexture = ( callback ) => textureNode.cache().context( { getUV: ( texNode ) => callback( texNode.uvNode || uv() ), forceUVContext: true } ); | ||
|  | 
 | ||
|  | 	const Hll = float( sampleTexture( ( uvNode ) => uvNode ) ); | ||
|  | 
 | ||
|  | 	return vec2( | ||
|  | 		float( sampleTexture( ( uvNode ) => uvNode.add( uvNode.dFdx() ) ) ).sub( Hll ), | ||
|  | 		float( sampleTexture( ( uvNode ) => uvNode.add( uvNode.dFdy() ) ) ).sub( Hll ) | ||
|  | 	).mul( bumpScale ); | ||
|  | 
 | ||
|  | } ); | ||
|  | 
 | ||
|  | // Evaluate the derivative of the height w.r.t. screen-space using forward differencing (listing 2)
 | ||
|  | 
 | ||
|  | const perturbNormalArb = tslFn( ( inputs ) => { | ||
|  | 
 | ||
|  | 	const { surf_pos, surf_norm, dHdxy } = inputs; | ||
|  | 
 | ||
|  | 	// normalize is done to ensure that the bump map looks the same regardless of the texture's scale
 | ||
|  | 	const vSigmaX = surf_pos.dFdx().normalize(); | ||
|  | 	const vSigmaY = surf_pos.dFdy().normalize(); | ||
|  | 	const vN = surf_norm; // normalized
 | ||
|  | 
 | ||
|  | 	const R1 = vSigmaY.cross( vN ); | ||
|  | 	const R2 = vN.cross( vSigmaX ); | ||
|  | 
 | ||
|  | 	const fDet = vSigmaX.dot( R1 ).mul( faceDirection ); | ||
|  | 
 | ||
|  | 	const vGrad = fDet.sign().mul( dHdxy.x.mul( R1 ).add( dHdxy.y.mul( R2 ) ) ); | ||
|  | 
 | ||
|  | 	return fDet.abs().mul( surf_norm ).sub( vGrad ).normalize(); | ||
|  | 
 | ||
|  | } ); | ||
|  | 
 | ||
|  | class BumpMapNode extends TempNode { | ||
|  | 
 | ||
|  | 	constructor( textureNode, scaleNode = null ) { | ||
|  | 
 | ||
|  | 		super( 'vec3' ); | ||
|  | 
 | ||
|  | 		this.textureNode = textureNode; | ||
|  | 		this.scaleNode = scaleNode; | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	setup() { | ||
|  | 
 | ||
|  | 		const bumpScale = this.scaleNode !== null ? this.scaleNode : 1; | ||
|  | 		const dHdxy = dHdxy_fwd( { textureNode: this.textureNode, bumpScale } ); | ||
|  | 
 | ||
|  | 		return perturbNormalArb( { | ||
|  | 			surf_pos: positionView, | ||
|  | 			surf_norm: normalView, | ||
|  | 			dHdxy | ||
|  | 		} ); | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | } | ||
|  | 
 | ||
|  | export default BumpMapNode; | ||
|  | 
 | ||
|  | export const bumpMap = nodeProxy( BumpMapNode ); | ||
|  | 
 | ||
|  | addNodeElement( 'bumpMap', bumpMap ); | ||
|  | 
 | ||
|  | addNodeClass( 'BumpMapNode', BumpMapNode ); |