-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathshader_manager.js
105 lines (91 loc) · 3.8 KB
/
shader_manager.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
export class ShaderManager {
constructor(scene) {
this.scene = scene;
material = new THREE.RawShaderMaterial({
vertexShader: vertexShaderCode,
fragmentShader: fragmentShaderCode,
glslVersion: THREE.GLSL3,
uniforms: {
uResolution: { value: new THREE.Vector2(window.innerWidth, window.innerHeight) },
uTime: { value: 0.0 },
uMouseCoord: { value: new THREE.Vector4(0.0, 0.0, 0.0, 0.0) },
},
});
this.isVertexShader = true;
this.customUniforms = {};
}
getCurrentShaderCode(isVertexShader) {
return isVertexShader ? vertexShaderCode : fragmentShaderCode;
}
addCustomUniform(name, type, value) {
this.customUniforms[name] = { type, value: this.parseValue(type, value) };
this.compileShader(this.getCurrentShaderCode(this.isVertexShader));
}
removeCustomUniform(name) {
if (this.customUniforms.hasOwnProperty(name)) {
delete this.customUniforms[name];
this.compileShader(this.getCurrentShaderCode(this.isVertexShader));
}
}
parseValue(type, value) {
if (type === 'float') return parseFloat(value);
if (type.startsWith('vec')) return this.parseVector(value, parseInt(type.charAt(3), 10));
console.error(`Invalid type: ${type}`);
return value;
}
parseVector(valueString, dimensions) {
const values = valueString.split(',').map(Number);
if (values.length !== dimensions || values.some(isNaN)) {
console.error(`Invalid vector: ${valueString}`);
return null;
}
return values;
}
compileShader(shaderCode) {
const newMaterial = new THREE.RawShaderMaterial({
vertexShader: this.isVertexShader ? shaderCode : material.vertexShader,
fragmentShader: !this.isVertexShader ? shaderCode : material.fragmentShader,
uniforms: {
...material.uniforms,
...Object.fromEntries(Object.entries(this.customUniforms).map(([k, v]) => [k, {value: v.value}])),
},
glslVersion: THREE.GLSL3,
});
material.dispose();
material = newMaterial;
this.updateSceneMaterials();
document.getElementById('shaderErrorContent').innerHTML = '🎉 no compile errors! 🎉';
const toggleButton = document.getElementById('toggleShaderError');
if (toggleButton) {
toggleButton.classList.remove('error', 'blink');
toggleButton.textContent = 'no compile errors! 🎉';
}
}
updateSceneMaterials() {
this.scene.traverse((object) => {
if (object.isMesh) {
object.material = material;
object.material.needsUpdate = true;
}
});
}
prepareShaderCode(shaderCode, isVertexShader) {
let uniformDeclarations = Object.keys(this.customUniforms)
.filter((uniformName) => {
const uniformDecl = `uniform ${this.customUniforms[uniformName].type} ${uniformName};`;
return !shaderCode.includes(uniformDecl);
})
.map((uniformName) => `uniform ${this.customUniforms[uniformName].type} ${uniformName};\n`)
.join('');
if (uniformDeclarations) {
if (isVertexShader) {
shaderCode = uniformDeclarations + shaderCode;
} else {
const precisionIndex = shaderCode.indexOf('precision');
const afterPrecision = precisionIndex >= 0 ? shaderCode.indexOf(';', precisionIndex) + 1 : 0;
shaderCode = shaderCode.slice(0, afterPrecision) + '\n' + uniformDeclarations + shaderCode.slice(afterPrecision);
}
}
return shaderCode;
}
}