threepipe
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

ExtendedShaderMaterial.ts 3.2KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. import {ShaderMaterial2} from './ShaderMaterial2'
  2. import {getTexelDecoding} from '../../three'
  3. import {
  4. BufferGeometry,
  5. Camera,
  6. ColorSpace,
  7. IUniform,
  8. LinearSRGBColorSpace,
  9. Object3D,
  10. Scene,
  11. Shader,
  12. ShaderMaterialParameters,
  13. Vector2,
  14. WebGLRenderer,
  15. } from 'three'
  16. import {shaderReplaceString} from '../../utils'
  17. import {IMaterialUserData} from '../IMaterial'
  18. // earlier it was ShaderMaterialEncodingSupport
  19. export class ExtendedShaderMaterial extends ShaderMaterial2 {
  20. declare ['constructor']: (typeof ExtendedShaderMaterial) & (typeof ShaderMaterial2)
  21. textures: {colorSpace: ColorSpace, id: string}[] = []
  22. declare userData: IMaterialUserData
  23. constructor(parameters: ShaderMaterialParameters, textureIds: string[], isRawShaderMaterial = false) {
  24. super(parameters, isRawShaderMaterial)
  25. this.setTextureIds(textureIds)
  26. }
  27. setTextureIds(ids: string[]) {
  28. if (this.textures.map(t=>t.id).join(';') !== ids.join(';')) {
  29. this.textures = ids.map(t=>({id: t, colorSpace: LinearSRGBColorSpace}))
  30. this.setDirty()
  31. }
  32. }
  33. private _setUniformTexSize(uniform?: IUniform, t?: {width: number, height: number}) {
  34. if (!t || !uniform) return
  35. const w = t?.width ?? 512
  36. const h = t?.height ?? 512
  37. const last = uniform.value
  38. if (!last.isVector2) console.warn('uniform is not a Vector2')
  39. if (last && Math.abs(last.x - w) + Math.abs(last.y - h) > 0.1) {
  40. last.x = w; last.y = h
  41. this.uniformsNeedUpdate = true
  42. }
  43. }
  44. onBeforeRender(renderer: WebGLRenderer, scene: Scene, camera: Camera, geometry: BufferGeometry, object: Object3D): void {
  45. this.uniforms.screenSize && this._setUniformTexSize(this.uniforms.screenSize, renderer.getRenderTarget() ?? renderer.getSize(new Vector2()))
  46. for (const item of this.textures) {
  47. const textureID = item.id
  48. const t = this.uniforms[textureID]?.value
  49. if (t) {
  50. this._setUniformTexSize(this.uniforms[textureID + 'Size'], t.image)
  51. if (t.colorSpace !== item.colorSpace) {
  52. item.colorSpace = t.colorSpace
  53. this.needsUpdate = true
  54. }
  55. }
  56. }
  57. super.onBeforeRender(renderer, scene, camera, geometry, object)
  58. }
  59. onBeforeCompile(s: Shader, renderer: WebGLRenderer) {
  60. const pars = '\n' + this.textures
  61. .map(t=>`uniform sampler2D ${t.id}; \n`
  62. + getTexelDecoding(t.id ?? 'input', t.colorSpace)).join('\n')
  63. if (s.fragmentShader.includes('#include <encodings_pars_fragment>')) {
  64. s.fragmentShader = shaderReplaceString(s.fragmentShader, '#include <encodings_pars_fragment>', pars, {append: true})
  65. } else if (s.fragmentShader.includes('precision highp float;')) {
  66. s.fragmentShader = shaderReplaceString(s.fragmentShader, 'precision highp float;', pars, {append: true})
  67. } else {
  68. s.fragmentShader = pars + s.fragmentShader
  69. }
  70. super.onBeforeCompile(s, renderer)
  71. }
  72. customProgramCacheKey(): string {
  73. return super.customProgramCacheKey() + this.textures.map(t=>t.id + t.colorSpace).join(';')
  74. }
  75. }