Skip to content

Commit

Permalink
chore: refactor shaders for composability
Browse files Browse the repository at this point in the history
  • Loading branch information
fallenoak committed Jan 7, 2024
1 parent d0f2598 commit 4ac0822
Show file tree
Hide file tree
Showing 8 changed files with 384 additions and 210 deletions.
3 changes: 2 additions & 1 deletion src/lib/map/terrain/TerrainMaterial.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as THREE from 'three';
import { fragmentShader, vertexShader } from './shaders.js';
import vertexShader from './shader/vertex.js';
import fragmentShader from './shader/fragment.js';

class TerrainMaterial extends THREE.RawShaderMaterial {
constructor(layerCount: number, layerTextures: THREE.Texture[], splatTexture: THREE.Texture) {
Expand Down
107 changes: 107 additions & 0 deletions src/lib/map/terrain/shader/fragment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { FUNCTION_APPLY_FOG, UNIFORM_FOG_COLOR, VARIABLE_FOG_FACTOR } from '../../../shader/fog.js';
import { composeShader } from '../../../shader/util.js';

const FRAGMENT_SHADER_PRECISION = 'highp float';

const FRAGMENT_SHADER_UNIFORMS = [
{ name: 'layerCount', type: 'int' },
{ name: 'layers[4]', type: 'sampler2D' },
{ name: 'splat', type: 'sampler2D' },
];

const FRAGMENT_SHADER_INPUTS = [
{ name: 'vLayerCoord', type: 'vec2' },
{ name: 'vSplatCoord', type: 'vec2' },
{ name: 'vLight', type: 'float' },
];

const FRAGMENT_SHADER_OUTPUTS = [{ name: 'color', type: 'vec4' }];

const FRAGMENT_SHADER_FUNCTION_BLEND_LAYER = `
vec4 blendLayer(vec4 color, vec4 layer, vec4 blend) {
return (layer * blend) + ((1.0 - blend) * color);
}
`;

const FRAGMENT_SHADER_FUNCTIONS = [FRAGMENT_SHADER_FUNCTION_BLEND_LAYER];

const FRAGMENT_SHADER_MAIN_LAYER_BLEND = `
vec4 layer;
vec4 blend;
// 1st layer
color = texture(layers[0], vLayerCoord);
blend = texture(splat, vSplatCoord);
// 2nd layer
if (layerCount > 1) {
layer = texture(layers[1], vLayerCoord);
color = blendLayer(color, layer, blend.rrrr);
}
if (layerCount > 2) {
layer = texture(layers[2], vLayerCoord);
color = blendLayer(color, layer, blend.gggg);
}
// 3rd layer
if (layerCount > 3) {
layer = texture(layers[3], vLayerCoord);
color = blendLayer(color, layer, blend.bbbb);
}
// Terrain is always opaque
color.a = 1.0;
`;

const FRAGMENT_SHADER_MAIN_LIGHTING = `
// Fixed lighting
vec3 lightDiffuse = normalize(vec3(0.25, 0.5, 1.0));
vec3 lightAmbient = normalize(vec3(0.5, 0.5, 0.5));
color.rgb *= lightDiffuse * vLight + lightAmbient;
`;

const FRAGMENT_SHADER_MAIN_FOG = `
// Apply fog
applyFog(color, ${UNIFORM_FOG_COLOR.name}, ${VARIABLE_FOG_FACTOR.name});
`;

const fragmentShader = (() => {
// Precision

const precision = FRAGMENT_SHADER_PRECISION;

// Uniforms

const uniforms = FRAGMENT_SHADER_UNIFORMS.slice(0);

uniforms.push(UNIFORM_FOG_COLOR);

// Inputs

const inputs = FRAGMENT_SHADER_INPUTS.slice(0);

inputs.push(VARIABLE_FOG_FACTOR);

// Outputs

const outputs = FRAGMENT_SHADER_OUTPUTS.slice(0);

// Functions

const functions = FRAGMENT_SHADER_FUNCTIONS.slice(0);

functions.push(FUNCTION_APPLY_FOG);

// Main

const main = [];

main.push(FRAGMENT_SHADER_MAIN_LAYER_BLEND);
main.push(FRAGMENT_SHADER_MAIN_LIGHTING);
main.push(FRAGMENT_SHADER_MAIN_FOG);

return composeShader(precision, uniforms, inputs, outputs, functions, main);
})();

export default fragmentShader;
99 changes: 99 additions & 0 deletions src/lib/map/terrain/shader/vertex.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import {
FUNCTION_CALCULATE_FOG_FACTOR,
UNIFORM_FOG_PARAMS,
VARIABLE_FOG_FACTOR,
} from '../../../shader/fog.js';
import { composeShader } from '../../../shader/util.js';

const VERTEX_SHADER_PRECISION = 'highp float';

const VERTEX_SHADER_UNIFORMS = [
{ name: 'modelMatrix', type: 'mat4' },
{ name: 'modelViewMatrix', type: 'mat4' },
{ name: 'projectionMatrix', type: 'mat4' },
{ name: 'cameraPosition', type: 'vec3 ' },
];

const VERTEX_SHADER_INPUTS = [
{ name: 'position', type: 'vec3' },
{ name: 'normal', type: 'vec3' },
];

const VERTEX_SHADER_OUTPUTS = [
{ name: 'vLayerCoord', type: 'vec2' },
{ name: 'vSplatCoord', type: 'vec2' },
{ name: 'vLight', type: 'float' },
];

const VERTEX_SHADER_FUNCTIONS = [];

const VERTEX_SHADER_MAIN_LAYER_COORD = `
// Terrain tileset textures repeat 8 times over the terrain chunk
vec4 layerScale = vec4(-0.24, -0.24, 0.0, 0.0);
vLayerCoord.xy = position.xy * layerScale.xy;
`;

const VERTEX_SHADER_MAIN_SPLAT_COORD = `
// Splat textures do not repeat over the terrain chunk
vec4 splatScale = vec4(-0.03, -0.03, 0.0, 0.0);
vSplatCoord.yx = position.xy * splatScale.xy;
`;

const VERTEX_SHADER_MAIN_LIGHTING = `
// TODO - Replace with lighting manager controlled value
vec3 lightDirection = vec3(-1, -1, -1);
vLight = dot(normal, -normalize(lightDirection));
`;

const VERTEX_SHADER_MAIN_FOG = `
// Calculate camera distance for fog coloring in fragment shader
vec4 worldPosition = modelMatrix * vec4(position, 1.0);
float cameraDistance = distance(cameraPosition, worldPosition.xyz);
${VARIABLE_FOG_FACTOR.name} = calculateFogFactor(${UNIFORM_FOG_PARAMS.name}, cameraDistance);
`;

const VERTEX_SHADER_MAIN_POSITION = `
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
`;

const vertexShader = (() => {
// Precision

const precision = VERTEX_SHADER_PRECISION;

// Uniforms

const uniforms = VERTEX_SHADER_UNIFORMS.slice(0);

uniforms.push(UNIFORM_FOG_PARAMS);

// Inputs

const inputs = VERTEX_SHADER_INPUTS.slice(0);

// Outputs

const outputs = VERTEX_SHADER_OUTPUTS.slice(0);

outputs.push(VARIABLE_FOG_FACTOR);

// Functions

const functions = VERTEX_SHADER_FUNCTIONS.slice(0);

functions.push(FUNCTION_CALCULATE_FOG_FACTOR);

// Main

const main = [];

main.push(VERTEX_SHADER_MAIN_LAYER_COORD);
main.push(VERTEX_SHADER_MAIN_SPLAT_COORD);
main.push(VERTEX_SHADER_MAIN_LIGHTING);
main.push(VERTEX_SHADER_MAIN_FOG);
main.push(VERTEX_SHADER_MAIN_POSITION);

return composeShader(precision, uniforms, inputs, outputs, functions, main);
})();

export default vertexShader;
116 changes: 0 additions & 116 deletions src/lib/map/terrain/shaders.ts

This file was deleted.

Loading

0 comments on commit 4ac0822

Please sign in to comment.