import { MeshStandardMaterial, Texture, Vector2 } from 'three'; export class TileMaterial extends MeshStandardMaterial { constructor(params, tileSizeX, tileSizeY) { super(params); this.tileSize = { value: new Vector2(tileSizeX / this.map.image.width, tileSizeY / this.map.image.height) }; } onBeforeCompile(shader) { shader.uniforms.tileSize = this.tileSize shader.vertexShader = shader.vertexShader.replace( `void main() {`, `varying vec2 vUv; varying vec2 vOffset; attribute vec2 offset; void main() { vUv = uv; vOffset = offset; gl_Position = projectionMatrix * modelViewMatrix * instanceMatrix * vec4(position, 1.0);` ) shader.fragmentShader = `varying vec2 vUv; varying vec2 vOffset; //uniform sampler2D map; uniform vec2 tileSize; varying vec2 vBumpMapUvOffset; ` + shader.fragmentShader shader.fragmentShader = shader.fragmentShader.replace( `#include `, `#ifdef USE_MAP vec4 sampledDiffuseColor = texture2D(map, vUv * tileSize + vOffset * tileSize); #ifdef DECODE_VIDEO_TEXTURE // use inline sRGB decode until browsers properly support SRGB8_ALPHA8 with video textures (#26516) sampledDiffuseColor = vec4( mix( pow( sampledDiffuseColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), sampledDiffuseColor.rgb * 0.0773993808, vec3( lessThanEqual( sampledDiffuseColor.rgb, vec3( 0.04045 ) ) ) ), sampledDiffuseColor.w ); #endif diffuseColor *= sampledDiffuseColor; #endif` ) shader.fragmentShader = shader.fragmentShader.replace( `#include `, `#ifdef USE_BUMPMAP uniform sampler2D bumpMap; uniform float bumpScale; // Bump Mapping Unparametrized Surfaces on the GPU by Morten S. Mikkelsen // https://mmikk.github.io/papers3d/mm_sfgrad_bump.pdf // Evaluate the derivative of the height w.r.t. screen-space using forward differencing (listing 2) vec2 dHdxy_fwd() { vec2 vBumpMapUvOffset = vBumpMapUv * tileSize + vOffset * tileSize; vec2 dSTdx = dFdx( vBumpMapUvOffset ); vec2 dSTdy = dFdy( vBumpMapUvOffset ); float Hll = bumpScale * texture2D( bumpMap, vBumpMapUvOffset ).x; float dBx = bumpScale * texture2D( bumpMap, vBumpMapUvOffset + dSTdx ).x - Hll; float dBy = bumpScale * texture2D( bumpMap, vBumpMapUvOffset + dSTdy ).x - Hll; return vec2( dBx, dBy ); } vec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy, float faceDirection ) { // normalize is done to ensure that the bump map looks the same regardless of the texture's scale vec3 vSigmaX = normalize( dFdx( surf_pos.xyz ) ); vec3 vSigmaY = normalize( dFdy( surf_pos.xyz ) ); vec3 vN = surf_norm; // normalized vec3 R1 = cross( vSigmaY, vN ); vec3 R2 = cross( vN, vSigmaX ); float fDet = dot( vSigmaX, R1 ) * faceDirection; vec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 ); return normalize( abs( fDet ) * surf_norm - vGrad ); } #endif` ) } }