216 lines
6.3 KiB
TypeScript
216 lines
6.3 KiB
TypeScript
import { ShaderMaterial, UniformsLib, UniformsUtils } from 'three';
|
|
import { WorldChunk } from '../../../common/world/WorldChunk';
|
|
import { ClientWorldTexture } from './client-world-texture';
|
|
|
|
// Adapted from the Lambert Material shader
|
|
// https://github.com/mrdoob/three.js/blob/44837d13a1bc0cf59824f3a6ddfab19ecd5ff435/src/renderers/shaders/ShaderLib/meshlambert.glsl.js
|
|
|
|
const vertex = /* glsl */ `
|
|
#include <common>
|
|
#include <uv_pars_vertex>
|
|
#include <uv2_pars_vertex>
|
|
#include <envmap_pars_vertex>
|
|
#include <bsdfs>
|
|
#include <lights_pars_begin>
|
|
#include <color_pars_vertex>
|
|
#include <fog_pars_vertex>
|
|
#include <morphtarget_pars_vertex>
|
|
#include <skinning_pars_vertex>
|
|
#include <shadowmap_pars_vertex>
|
|
#include <logdepthbuf_pars_vertex>
|
|
#include <clipping_planes_pars_vertex>
|
|
|
|
varying vec3 vLightFront;
|
|
varying vec3 vIndirectFront;
|
|
varying vec2 vUv;
|
|
|
|
void main() {
|
|
vUv = uv;
|
|
#include <uv_vertex>
|
|
#include <uv2_vertex>
|
|
#include <color_vertex>
|
|
#include <morphcolor_vertex>
|
|
#include <beginnormal_vertex>
|
|
#include <morphnormal_vertex>
|
|
#include <skinbase_vertex>
|
|
#include <skinnormal_vertex>
|
|
#include <defaultnormal_vertex>
|
|
#include <begin_vertex>
|
|
#include <morphtarget_vertex>
|
|
#include <skinning_vertex>
|
|
#include <project_vertex>
|
|
#include <logdepthbuf_vertex>
|
|
#include <clipping_planes_vertex>
|
|
#include <worldpos_vertex>
|
|
#include <envmap_vertex>
|
|
#include <lights_lambert_vertex>
|
|
#include <shadowmap_vertex>
|
|
#include <fog_vertex>
|
|
}
|
|
`;
|
|
|
|
const fragment = /* glsl */ `
|
|
|
|
varying vec3 vLightFront;
|
|
varying vec3 vIndirectFront;
|
|
|
|
#include <common>
|
|
#include <packing>
|
|
#include <dithering_pars_fragment>
|
|
#include <color_pars_fragment>
|
|
#include <uv_pars_fragment>
|
|
#include <uv2_pars_fragment>
|
|
#include <map_pars_fragment>
|
|
#include <alphamap_pars_fragment>
|
|
#include <alphatest_pars_fragment>
|
|
#include <aomap_pars_fragment>
|
|
#include <lightmap_pars_fragment>
|
|
#include <emissivemap_pars_fragment>
|
|
#include <envmap_common_pars_fragment>
|
|
#include <envmap_pars_fragment>
|
|
#include <cube_uv_reflection_fragment>
|
|
#include <bsdfs>
|
|
#include <lights_pars_begin>
|
|
#include <fog_pars_fragment>
|
|
#include <shadowmap_pars_fragment>
|
|
#include <shadowmask_pars_fragment>
|
|
#include <specularmap_pars_fragment>
|
|
#include <logdepthbuf_pars_fragment>
|
|
#include <clipping_planes_pars_fragment>
|
|
|
|
uniform sampler2D backgroundTex;
|
|
uniform sampler2D noiseTex;
|
|
uniform sampler2D rTex;
|
|
uniform sampler2D gTex;
|
|
uniform sampler2D bTex;
|
|
uniform sampler2D splatMap;
|
|
|
|
uniform float chunkSize;
|
|
|
|
varying vec2 vUv;
|
|
float sum( vec3 v ) { return v.x+v.y+v.z; }
|
|
|
|
// https://www.shadertoy.com/view/lt2GDd
|
|
vec4 textureNoTile(sampler2D samp, in vec2 x)
|
|
{
|
|
float k = texture( noiseTex, 0.005*x ).x; // cheap (cache friendly) lookup
|
|
|
|
vec2 duvdx = dFdx( x );
|
|
vec2 duvdy = dFdx( x );
|
|
|
|
float l = k*8.0;
|
|
float f = fract(l);
|
|
|
|
float ia = floor(l+0.5);
|
|
float ib = floor(l);
|
|
f = min(f, 1.0-f)*2.0;
|
|
|
|
vec2 offa = sin(vec2(3.0,7.0)*ia); // can replace with any other hash
|
|
vec2 offb = sin(vec2(3.0,7.0)*ib); // can replace with any other hash
|
|
|
|
vec3 cola = textureGrad( samp, x + 0.8 *offa, duvdx, duvdy ).xyz;
|
|
vec3 colb = textureGrad( samp, x + 0.8 *offb, duvdx, duvdy ).xyz;
|
|
|
|
return vec4(mix( cola, colb, smoothstep(0.2,0.8,f-0.1*sum(cola-colb)) ), 1.0);
|
|
}
|
|
|
|
void main() {
|
|
#include <clipping_planes_fragment>
|
|
|
|
vec4 splatMapColor = texture2D(splatMap, vUv);
|
|
float backTextureAmount = 1.0 - (splatMapColor.r + splatMapColor.g + splatMapColor.b);
|
|
vec2 tiledCoords = vUv * chunkSize;
|
|
vec4 backgroundTextureColor = textureNoTile(backgroundTex, tiledCoords) * backTextureAmount;
|
|
vec4 rTextureAmount = textureNoTile(rTex, tiledCoords) * splatMapColor.r;
|
|
vec4 gTextureAmount = textureNoTile(gTex, tiledCoords) * splatMapColor.g;
|
|
vec4 bTextureAmount = textureNoTile(bTex, tiledCoords) * splatMapColor.b;
|
|
|
|
vec4 diffuseColor = backgroundTextureColor + rTextureAmount + gTextureAmount + bTextureAmount;
|
|
|
|
ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );
|
|
|
|
#include <logdepthbuf_fragment>
|
|
#include <map_fragment>
|
|
#include <color_fragment>
|
|
#include <alphamap_fragment>
|
|
#include <alphatest_fragment>
|
|
#include <specularmap_fragment>
|
|
#include <emissivemap_fragment>
|
|
|
|
reflectedLight.indirectDiffuse += vIndirectFront;
|
|
|
|
#include <lightmap_fragment>
|
|
reflectedLight.indirectDiffuse *= BRDF_Lambert( diffuseColor.rgb );
|
|
reflectedLight.directDiffuse = vLightFront;
|
|
reflectedLight.directDiffuse *= BRDF_Lambert( diffuseColor.rgb ) * getShadowMask();
|
|
|
|
#include <aomap_fragment>
|
|
vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse;
|
|
|
|
#include <envmap_fragment>
|
|
#include <output_fragment>
|
|
#include <tonemapping_fragment>
|
|
#include <encodings_fragment>
|
|
#include <fog_fragment>
|
|
#include <premultiplied_alpha_fragment>
|
|
#include <dithering_fragment>
|
|
}
|
|
`;
|
|
|
|
export class ClientWorldChunkShader {
|
|
public shader!: ShaderMaterial;
|
|
|
|
constructor(public textureList: Map<string, ClientWorldTexture>) {}
|
|
|
|
initialize() {
|
|
this.shader = new ShaderMaterial({
|
|
vertexShader: vertex,
|
|
fragmentShader: fragment,
|
|
lights: true,
|
|
uniforms: UniformsUtils.merge([
|
|
UniformsLib.common,
|
|
UniformsLib.specularmap,
|
|
UniformsLib.envmap,
|
|
UniformsLib.aomap,
|
|
UniformsLib.lightmap,
|
|
UniformsLib.emissivemap,
|
|
UniformsLib.fog,
|
|
UniformsLib.lights,
|
|
{
|
|
backgroundTex: { value: null, type: 't' },
|
|
noiseTex: { value: null, type: 't' },
|
|
rTex: { value: null, type: 't' },
|
|
gTex: { value: null, type: 't' },
|
|
bTex: { value: null, type: 't' },
|
|
splatMap: { value: null, type: 't' },
|
|
chunkSize: { value: null },
|
|
},
|
|
]),
|
|
});
|
|
}
|
|
|
|
public setNoise(noise: ClientWorldTexture) {
|
|
this.shader.uniforms.noiseTex.value = noise.texture;
|
|
}
|
|
|
|
public getShader(
|
|
chunk: WorldChunk,
|
|
splatMap: string,
|
|
textureList: string[],
|
|
): ShaderMaterial {
|
|
const clone = this.shader.clone();
|
|
|
|
const splat = this.textureList.get(splatMap);
|
|
const [bg, r, g, b] = textureList.map((item) => this.textureList.get(item));
|
|
|
|
clone.uniforms.chunkSize.value = chunk.size / 2;
|
|
clone.uniforms.splatMap.value = splat.texture;
|
|
clone.uniforms.backgroundTex.value = bg.texture;
|
|
clone.uniforms.rTex.value = r.texture;
|
|
clone.uniforms.gTex.value = g.texture;
|
|
clone.uniforms.bTex.value = b.texture;
|
|
|
|
return clone;
|
|
}
|
|
}
|