-
Notifications
You must be signed in to change notification settings - Fork 60
/
vanilla.ts
116 lines (92 loc) · 3.02 KB
/
vanilla.ts
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
106
107
108
109
110
111
112
113
114
115
116
import { IUniform, Material, MathUtils } from 'three'
import { iCSMProps, iCSMShader } from './types'
import * as PATCH_MAP from './patchMaps'
export default class CustomShaderMaterial extends Material {
uniforms: { [key: string]: IUniform<any> }
constructor(
baseMaterial: iCSMProps['baseMaterial'],
fragmentShader?: iCSMProps['fragmentShader'],
vertexShader?: iCSMProps['vertexShader'],
uniforms?: iCSMProps['uniforms'],
opts?: any
) {
// @ts-ignore
const base = new baseMaterial(opts)
super()
for (const key in base) {
// @ts-ignore
if (this[key] === undefined) this[key] = 0
// @ts-ignore
this[key] = base[key]
}
console.log(this)
const parsedFragmentShdaer = this.parseShader(fragmentShader)
const parsedVertexShdaer = this.parseShader(vertexShader)
this.uniforms = uniforms || {}
this.customProgramCacheKey = () => {
return this.uuid
}
this.onBeforeCompile = (shader) => {
if (parsedFragmentShdaer) {
const patchedFragmentShdaer = this.patchShader(parsedFragmentShdaer, shader.fragmentShader, PATCH_MAP.FRAG)
shader.fragmentShader = patchedFragmentShdaer
}
if (parsedVertexShdaer) {
const patchedVertexShdaer = this.patchShader(parsedVertexShdaer, shader.vertexShader, PATCH_MAP.VERT)
shader.vertexShader = patchedVertexShdaer
}
shader.uniforms = { ...shader.uniforms, ...this.uniforms }
this.uniforms = shader.uniforms
this.needsUpdate = true
}
}
private patchShader(
customShader: iCSMShader,
shader: string,
patchMap: {
[key: string]: string
}
): string {
let patchedShader: string = shader
Object.keys(patchMap).forEach((key: string) => {
const v = patchMap[key]!
patchedShader = replaceAll(patchedShader, key, v)
})
patchedShader = patchedShader.replace(
'void main() {',
`
${customShader.header}
void main() {
vec3 csm_Position;
vec3 csm_Normal;
vec4 csm_DiffuseColor;
float csm_PointSize;
${customShader.main}
`
)
patchedShader = customShader.defines + patchedShader
return patchedShader
}
private parseShader(shader?: string): iCSMShader | undefined {
if (!shader) return
const parsedShader: iCSMShader = {
defines: '',
header: '',
main: '',
}
const main = shader.match(/void\s*main\s*\w*\s*\([\w\s,]*\)\s*{([\w\W]*?)}/g)
if (main?.length) {
const mainBody = main[0].match(/\{((.|\n)*?)\}/g)
if (mainBody?.length) {
parsedShader.main = mainBody[0]
}
const rest = shader.replace(main[0], '')
const defines = rest.match(/#(.*?;)/g) || []
const header = defines.reduce((prev, curr) => prev.replace(curr, ''), rest)
parsedShader.header = header
parsedShader.defines = defines.join('\n')
}
return parsedShader
}
}
const replaceAll = (str: string, find: string, rep: string) => str.split(find).join(rep)