Source: core/renderers/webgl/WebGLRenderer.js

core/renderers/webgl/WebGLRenderer.js

  1. import SystemRenderer from '../SystemRenderer';
  2. import MaskManager from './managers/MaskManager';
  3. import StencilManager from './managers/StencilManager';
  4. import FilterManager from './managers/FilterManager';
  5. import RenderTarget from './utils/RenderTarget';
  6. import ObjectRenderer from './utils/ObjectRenderer';
  7. import TextureManager from './TextureManager';
  8. import BaseTexture from '../../textures/BaseTexture';
  9. import TextureGarbageCollector from './TextureGarbageCollector';
  10. import WebGLState from './WebGLState';
  11. import mapWebGLDrawModesToPixi from './utils/mapWebGLDrawModesToPixi';
  12. import validateContext from './utils/validateContext';
  13. import { pluginTarget } from '../../utils';
  14. // 修改依赖库应对小程序环境
  15. import glCore from '../../../dependencies/pixi-gl-core/';
  16. // import glCore from 'pixi-gl-core';
  17. import { RENDERER_TYPE } from '../../const';
  18. let CONTEXT_UID = 0;
  19. /**
  20. * The WebGLRenderer draws the scene and all its content onto a webGL enabled canvas. This renderer
  21. * should be used for browsers that support webGL. This Render works by automatically managing webGLBatchs.
  22. * So no need for Sprite Batches or Sprite Clouds.
  23. * Don't forget to add the view to your DOM or you will not see anything :)
  24. *
  25. * @class
  26. * @memberof PIXI
  27. * @extends PIXI.SystemRenderer
  28. */
  29. export default class WebGLRenderer extends SystemRenderer
  30. {
  31. // eslint-disable-next-line valid-jsdoc
  32. /**
  33. *
  34. * @param {object} [options] - The optional renderer parameters
  35. * @param {number} [options.width=800] - the width of the screen
  36. * @param {number} [options.height=600] - the height of the screen
  37. * @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
  38. * @param {boolean} [options.transparent=false] - If the render view is transparent, default false
  39. * @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
  40. * @param {boolean} [options.antialias=false] - sets antialias. If not available natively then FXAA
  41. * antialiasing is used
  42. * @param {boolean} [options.forceFXAA=false] - forces FXAA antialiasing to be used over native.
  43. * FXAA is faster, but may not always look as great
  44. * @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer.
  45. * The resolution of the renderer retina would be 2.
  46. * @param {boolean} [options.clearBeforeRender=true] - This sets if the renderer will clear
  47. * the canvas or not before the new render pass. If you wish to set this to false, you *must* set
  48. * preserveDrawingBuffer to `true`.
  49. * @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation,
  50. * enable this if you need to call toDataUrl on the webgl context.
  51. * @param {boolean} [options.roundPixels=false] - If true PixiJS will Math.floor() x/y values when
  52. * rendering, stopping pixel interpolation.
  53. * @param {number} [options.backgroundColor=0x000000] - The background color of the rendered area
  54. * (shown if not transparent).
  55. * @param {boolean} [options.legacy=false] - If true PixiJS will aim to ensure compatibility
  56. * with older / less advanced devices. If you experience unexplained flickering try setting this to true.
  57. * @param {string} [options.powerPreference] - Parameter passed to webgl context, set to "high-performance"
  58. * for devices with dual graphics card
  59. */
  60. constructor(options, arg2, arg3)
  61. {
  62. super('WebGL', options, arg2, arg3);
  63. this.legacy = this.options.legacy;
  64. if (this.legacy)
  65. {
  66. glCore.VertexArrayObject.FORCE_NATIVE = true;
  67. }
  68. /**
  69. * The type of this renderer as a standardised const
  70. *
  71. * @member {number}
  72. * @see PIXI.RENDERER_TYPE
  73. */
  74. this.type = RENDERER_TYPE.WEBGL;
  75. this.handleContextLost = this.handleContextLost.bind(this);
  76. this.handleContextRestored = this.handleContextRestored.bind(this);
  77. this.view.addEventListener('webglcontextlost', this.handleContextLost, false);
  78. this.view.addEventListener('webglcontextrestored', this.handleContextRestored, false);
  79. /**
  80. * The options passed in to create a new webgl context.
  81. *
  82. * @member {object}
  83. * @private
  84. */
  85. this._contextOptions = {
  86. alpha: this.transparent,
  87. antialias: this.options.antialias,
  88. premultipliedAlpha: this.transparent && this.transparent !== 'notMultiplied',
  89. stencil: true,
  90. preserveDrawingBuffer: this.options.preserveDrawingBuffer,
  91. powerPreference: this.options.powerPreference,
  92. };
  93. this._backgroundColorRgba[3] = this.transparent ? 0 : 1;
  94. /**
  95. * Manages the masks using the stencil buffer.
  96. *
  97. * @member {PIXI.MaskManager}
  98. */
  99. this.maskManager = new MaskManager(this);
  100. /**
  101. * Manages the stencil buffer.
  102. *
  103. * @member {PIXI.StencilManager}
  104. */
  105. this.stencilManager = new StencilManager(this);
  106. /**
  107. * An empty renderer.
  108. *
  109. * @member {PIXI.ObjectRenderer}
  110. */
  111. this.emptyRenderer = new ObjectRenderer(this);
  112. /**
  113. * The currently active ObjectRenderer.
  114. *
  115. * @member {PIXI.ObjectRenderer}
  116. */
  117. this.currentRenderer = this.emptyRenderer;
  118. /**
  119. * Manages textures
  120. * @member {PIXI.TextureManager}
  121. */
  122. this.textureManager = null;
  123. /**
  124. * Manages the filters.
  125. *
  126. * @member {PIXI.FilterManager}
  127. */
  128. this.filterManager = null;
  129. this.initPlugins();
  130. /**
  131. * The current WebGL rendering context, it is created here
  132. *
  133. * @member {WebGLRenderingContext}
  134. */
  135. // initialize the context so it is ready for the managers.
  136. if (this.options.context)
  137. {
  138. // checks to see if a context is valid..
  139. validateContext(this.options.context);
  140. }
  141. this.gl = this.options.context || glCore.createContext(this.view, this._contextOptions);
  142. this.CONTEXT_UID = CONTEXT_UID++;
  143. /**
  144. * The currently active ObjectRenderer.
  145. *
  146. * @member {PIXI.WebGLState}
  147. */
  148. this.state = new WebGLState(this.gl);
  149. this.renderingToScreen = true;
  150. /**
  151. * Holds the current state of textures bound to the GPU.
  152. * @type {Array}
  153. */
  154. this.boundTextures = null;
  155. /**
  156. * Holds the current shader
  157. *
  158. * @member {PIXI.Shader}
  159. */
  160. this._activeShader = null;
  161. this._activeVao = null;
  162. /**
  163. * Holds the current render target
  164. *
  165. * @member {PIXI.RenderTarget}
  166. */
  167. this._activeRenderTarget = null;
  168. this._initContext();
  169. // map some webGL blend and drawmodes..
  170. this.drawModes = mapWebGLDrawModesToPixi(this.gl);
  171. this._nextTextureLocation = 0;
  172. this.setBlendMode(0);
  173. /**
  174. * Fired after rendering finishes.
  175. *
  176. * @event PIXI.WebGLRenderer#postrender
  177. */
  178. /**
  179. * Fired before rendering starts.
  180. *
  181. * @event PIXI.WebGLRenderer#prerender
  182. */
  183. /**
  184. * Fired when the WebGL context is set.
  185. *
  186. * @event PIXI.WebGLRenderer#context
  187. * @param {WebGLRenderingContext} gl - WebGL context.
  188. */
  189. }
  190. /**
  191. * Creates the WebGL context
  192. *
  193. * @private
  194. */
  195. _initContext()
  196. {
  197. const gl = this.gl;
  198. // restore a context if it was previously lost
  199. if (gl.isContextLost() && gl.getExtension('WEBGL_lose_context'))
  200. {
  201. gl.getExtension('WEBGL_lose_context').restoreContext();
  202. }
  203. const maxTextures = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS);
  204. this._activeShader = null;
  205. this._activeVao = null;
  206. this.boundTextures = new Array(maxTextures);
  207. this.emptyTextures = new Array(maxTextures);
  208. /**
  209. * Did someone temper with textures state? We'll overwrite them when we need to unbind something.
  210. * @member {boolean}
  211. * @private
  212. */
  213. this._unknownBoundTextures = false;
  214. // create a texture manager...
  215. this.textureManager = new TextureManager(this);
  216. this.filterManager = new FilterManager(this);
  217. this.textureGC = new TextureGarbageCollector(this);
  218. this.state.resetToDefault();
  219. this.rootRenderTarget = new RenderTarget(gl, this.width, this.height, null, this.resolution, true);
  220. this.rootRenderTarget.clearColor = this._backgroundColorRgba;
  221. this.bindRenderTarget(this.rootRenderTarget);
  222. // now lets fill up the textures with empty ones!
  223. const emptyGLTexture = new glCore.GLTexture.fromData(gl, null, 1, 1);
  224. const tempObj = { _glTextures: {} };
  225. tempObj._glTextures[this.CONTEXT_UID] = {};
  226. for (let i = 0; i < maxTextures; i++)
  227. {
  228. const empty = new BaseTexture();
  229. empty._glTextures[this.CONTEXT_UID] = emptyGLTexture;
  230. this.boundTextures[i] = tempObj;
  231. this.emptyTextures[i] = empty;
  232. this.bindTexture(null, i);
  233. }
  234. this.emit('context', gl);
  235. // setup the width/height properties and gl viewport
  236. this.resize(this.screen.width, this.screen.height);
  237. }
  238. /**
  239. * Renders the object to its webGL view
  240. *
  241. * @param {PIXI.DisplayObject} displayObject - the object to be rendered
  242. * @param {PIXI.RenderTexture} renderTexture - The render texture to render to.
  243. * @param {boolean} [clear] - Should the canvas be cleared before the new render
  244. * @param {PIXI.Matrix} [transform] - A transform to apply to the render texture before rendering.
  245. * @param {boolean} [skipUpdateTransform] - Should we skip the update transform pass?
  246. */
  247. render(displayObject, renderTexture, clear, transform, skipUpdateTransform)
  248. {
  249. // can be handy to know!
  250. this.renderingToScreen = !renderTexture;
  251. this.emit('prerender');
  252. // no point rendering if our context has been blown up!
  253. if (!this.gl || this.gl.isContextLost())
  254. {
  255. return;
  256. }
  257. this._nextTextureLocation = 0;
  258. if (!renderTexture)
  259. {
  260. this._lastObjectRendered = displayObject;
  261. }
  262. if (!skipUpdateTransform)
  263. {
  264. // update the scene graph
  265. const cacheParent = displayObject.parent;
  266. displayObject.parent = this._tempDisplayObjectParent;
  267. displayObject.updateTransform();
  268. displayObject.parent = cacheParent;
  269. // displayObject.hitArea = //TODO add a temp hit area
  270. }
  271. this.bindRenderTexture(renderTexture, transform);
  272. this.currentRenderer.start();
  273. if (clear !== undefined ? clear : this.clearBeforeRender)
  274. {
  275. this._activeRenderTarget.clear();
  276. }
  277. displayObject.renderWebGL(this);
  278. // apply transform..
  279. this.currentRenderer.flush();
  280. // this.setObjectRenderer(this.emptyRenderer);
  281. this.textureGC.update();
  282. this.emit('postrender');
  283. }
  284. /**
  285. * Changes the current renderer to the one given in parameter
  286. *
  287. * @param {PIXI.ObjectRenderer} objectRenderer - The object renderer to use.
  288. */
  289. setObjectRenderer(objectRenderer)
  290. {
  291. if (this.currentRenderer === objectRenderer)
  292. {
  293. return;
  294. }
  295. this.currentRenderer.stop();
  296. this.currentRenderer = objectRenderer;
  297. this.currentRenderer.start();
  298. }
  299. /**
  300. * This should be called if you wish to do some custom rendering
  301. * It will basically render anything that may be batched up such as sprites
  302. *
  303. */
  304. flush()
  305. {
  306. this.setObjectRenderer(this.emptyRenderer);
  307. }
  308. /**
  309. * Resizes the webGL view to the specified width and height.
  310. *
  311. * @param {number} screenWidth - the new width of the screen
  312. * @param {number} screenHeight - the new height of the screen
  313. */
  314. resize(screenWidth, screenHeight)
  315. {
  316. // if(width * this.resolution === this.width && height * this.resolution === this.height)return;
  317. SystemRenderer.prototype.resize.call(this, screenWidth, screenHeight);
  318. this.rootRenderTarget.resize(screenWidth, screenHeight);
  319. if (this._activeRenderTarget === this.rootRenderTarget)
  320. {
  321. this.rootRenderTarget.activate();
  322. if (this._activeShader)
  323. {
  324. this._activeShader.uniforms.projectionMatrix = this.rootRenderTarget.projectionMatrix.toArray(true);
  325. }
  326. }
  327. }
  328. /**
  329. * Resizes the webGL view to the specified width and height.
  330. *
  331. * @param {number} blendMode - the desired blend mode
  332. */
  333. setBlendMode(blendMode)
  334. {
  335. this.state.setBlendMode(blendMode);
  336. }
  337. /**
  338. * Erases the active render target and fills the drawing area with a colour
  339. *
  340. * @param {number} [clearColor] - The colour
  341. */
  342. clear(clearColor)
  343. {
  344. this._activeRenderTarget.clear(clearColor);
  345. }
  346. /**
  347. * Sets the transform of the active render target to the given matrix
  348. *
  349. * @param {PIXI.Matrix} matrix - The transformation matrix
  350. */
  351. setTransform(matrix)
  352. {
  353. this._activeRenderTarget.transform = matrix;
  354. }
  355. /**
  356. * Erases the render texture and fills the drawing area with a colour
  357. *
  358. * @param {PIXI.RenderTexture} renderTexture - The render texture to clear
  359. * @param {number} [clearColor] - The colour
  360. * @return {PIXI.WebGLRenderer} Returns itself.
  361. */
  362. clearRenderTexture(renderTexture, clearColor)
  363. {
  364. const baseTexture = renderTexture.baseTexture;
  365. const renderTarget = baseTexture._glRenderTargets[this.CONTEXT_UID];
  366. if (renderTarget)
  367. {
  368. renderTarget.clear(clearColor);
  369. }
  370. return this;
  371. }
  372. /**
  373. * Binds a render texture for rendering
  374. *
  375. * @param {PIXI.RenderTexture} renderTexture - The render texture to render
  376. * @param {PIXI.Matrix} transform - The transform to be applied to the render texture
  377. * @return {PIXI.WebGLRenderer} Returns itself.
  378. */
  379. bindRenderTexture(renderTexture, transform)
  380. {
  381. let renderTarget;
  382. if (renderTexture)
  383. {
  384. const baseTexture = renderTexture.baseTexture;
  385. if (!baseTexture._glRenderTargets[this.CONTEXT_UID])
  386. {
  387. // bind the current texture
  388. this.textureManager.updateTexture(baseTexture, 0);
  389. }
  390. this.unbindTexture(baseTexture);
  391. renderTarget = baseTexture._glRenderTargets[this.CONTEXT_UID];
  392. renderTarget.setFrame(renderTexture.frame);
  393. }
  394. else
  395. {
  396. renderTarget = this.rootRenderTarget;
  397. }
  398. renderTarget.transform = transform;
  399. this.bindRenderTarget(renderTarget);
  400. return this;
  401. }
  402. /**
  403. * Changes the current render target to the one given in parameter
  404. *
  405. * @param {PIXI.RenderTarget} renderTarget - the new render target
  406. * @return {PIXI.WebGLRenderer} Returns itself.
  407. */
  408. bindRenderTarget(renderTarget)
  409. {
  410. if (renderTarget !== this._activeRenderTarget)
  411. {
  412. this._activeRenderTarget = renderTarget;
  413. renderTarget.activate();
  414. if (this._activeShader)
  415. {
  416. this._activeShader.uniforms.projectionMatrix = renderTarget.projectionMatrix.toArray(true);
  417. }
  418. this.stencilManager.setMaskStack(renderTarget.stencilMaskStack);
  419. }
  420. return this;
  421. }
  422. /**
  423. * Changes the current shader to the one given in parameter
  424. *
  425. * @param {PIXI.Shader} shader - the new shader
  426. * @param {boolean} [autoProject=true] - Whether automatically set the projection matrix
  427. * @return {PIXI.WebGLRenderer} Returns itself.
  428. */
  429. bindShader(shader, autoProject)
  430. {
  431. // TODO cache
  432. if (this._activeShader !== shader)
  433. {
  434. this._activeShader = shader;
  435. shader.bind();
  436. // `autoProject` normally would be a default parameter set to true
  437. // but because of how Babel transpiles default parameters
  438. // it hinders the performance of this method.
  439. if (autoProject !== false)
  440. {
  441. // automatically set the projection matrix
  442. shader.uniforms.projectionMatrix = this._activeRenderTarget.projectionMatrix.toArray(true);
  443. }
  444. }
  445. return this;
  446. }
  447. /**
  448. * Binds the texture. This will return the location of the bound texture.
  449. * It may not be the same as the one you pass in. This is due to optimisation that prevents
  450. * needless binding of textures. For example if the texture is already bound it will return the
  451. * current location of the texture instead of the one provided. To bypass this use force location
  452. *
  453. * @param {PIXI.Texture} texture - the new texture
  454. * @param {number} location - the suggested texture location
  455. * @param {boolean} forceLocation - force the location
  456. * @return {number} bound texture location
  457. */
  458. bindTexture(texture, location, forceLocation)
  459. {
  460. texture = texture || this.emptyTextures[location];
  461. texture = texture.baseTexture || texture;
  462. texture.touched = this.textureGC.count;
  463. if (!forceLocation)
  464. {
  465. // TODO - maybe look into adding boundIds.. save us the loop?
  466. for (let i = 0; i < this.boundTextures.length; i++)
  467. {
  468. if (this.boundTextures[i] === texture)
  469. {
  470. return i;
  471. }
  472. }
  473. if (location === undefined)
  474. {
  475. this._nextTextureLocation++;
  476. this._nextTextureLocation %= this.boundTextures.length;
  477. location = this.boundTextures.length - this._nextTextureLocation - 1;
  478. }
  479. }
  480. else
  481. {
  482. location = location || 0;
  483. }
  484. const gl = this.gl;
  485. const glTexture = texture._glTextures[this.CONTEXT_UID];
  486. if (!glTexture)
  487. {
  488. // this will also bind the texture..
  489. this.textureManager.updateTexture(texture, location);
  490. }
  491. else
  492. {
  493. // bind the current texture
  494. this.boundTextures[location] = texture;
  495. gl.activeTexture(gl.TEXTURE0 + location);
  496. gl.bindTexture(gl.TEXTURE_2D, glTexture.texture);
  497. }
  498. return location;
  499. }
  500. /**
  501. * unbinds the texture ...
  502. *
  503. * @param {PIXI.Texture} texture - the texture to unbind
  504. * @return {PIXI.WebGLRenderer} Returns itself.
  505. */
  506. unbindTexture(texture)
  507. {
  508. const gl = this.gl;
  509. texture = texture.baseTexture || texture;
  510. if (this._unknownBoundTextures)
  511. {
  512. this._unknownBoundTextures = false;
  513. // someone changed webGL state,
  514. // we have to be sure that our texture does not appear in multitexture renderer samplers
  515. for (let i = 0; i < this.boundTextures.length; i++)
  516. {
  517. if (this.boundTextures[i] === this.emptyTextures[i])
  518. {
  519. gl.activeTexture(gl.TEXTURE0 + i);
  520. gl.bindTexture(gl.TEXTURE_2D, this.emptyTextures[i]._glTextures[this.CONTEXT_UID].texture);
  521. }
  522. }
  523. }
  524. for (let i = 0; i < this.boundTextures.length; i++)
  525. {
  526. if (this.boundTextures[i] === texture)
  527. {
  528. this.boundTextures[i] = this.emptyTextures[i];
  529. gl.activeTexture(gl.TEXTURE0 + i);
  530. gl.bindTexture(gl.TEXTURE_2D, this.emptyTextures[i]._glTextures[this.CONTEXT_UID].texture);
  531. }
  532. }
  533. return this;
  534. }
  535. /**
  536. * Creates a new VAO from this renderer's context and state.
  537. *
  538. * @return {VertexArrayObject} The new VAO.
  539. */
  540. createVao()
  541. {
  542. return new glCore.VertexArrayObject(this.gl, this.state.attribState);
  543. }
  544. /**
  545. * Changes the current Vao to the one given in parameter
  546. *
  547. * @param {PIXI.VertexArrayObject} vao - the new Vao
  548. * @return {PIXI.WebGLRenderer} Returns itself.
  549. */
  550. bindVao(vao)
  551. {
  552. if (this._activeVao === vao)
  553. {
  554. return this;
  555. }
  556. if (vao)
  557. {
  558. vao.bind();
  559. }
  560. else if (this._activeVao)
  561. {
  562. // TODO this should always be true i think?
  563. this._activeVao.unbind();
  564. }
  565. this._activeVao = vao;
  566. return this;
  567. }
  568. /**
  569. * Resets the WebGL state so you can render things however you fancy!
  570. *
  571. * @return {PIXI.WebGLRenderer} Returns itself.
  572. */
  573. reset()
  574. {
  575. this.setObjectRenderer(this.emptyRenderer);
  576. this.bindVao(null);
  577. this._activeShader = null;
  578. this._activeRenderTarget = this.rootRenderTarget;
  579. this._unknownBoundTextures = true;
  580. for (let i = 0; i < this.boundTextures.length; i++)
  581. {
  582. this.boundTextures[i] = this.emptyTextures[i];
  583. }
  584. // bind the main frame buffer (the screen);
  585. this.rootRenderTarget.activate();
  586. this.state.resetToDefault();
  587. return this;
  588. }
  589. /**
  590. * Handles a lost webgl context
  591. *
  592. * @private
  593. * @param {WebGLContextEvent} event - The context lost event.
  594. */
  595. handleContextLost(event)
  596. {
  597. event.preventDefault();
  598. }
  599. /**
  600. * Handles a restored webgl context
  601. *
  602. * @private
  603. */
  604. handleContextRestored()
  605. {
  606. this.textureManager.removeAll();
  607. this.filterManager.destroy(true);
  608. this._initContext();
  609. }
  610. /**
  611. * Removes everything from the renderer (event listeners, spritebatch, etc...)
  612. *
  613. * @param {boolean} [removeView=false] - Removes the Canvas element from the DOM.
  614. * See: https://github.com/pixijs/pixi.js/issues/2233
  615. */
  616. destroy(removeView)
  617. {
  618. this.destroyPlugins();
  619. // remove listeners
  620. this.view.removeEventListener('webglcontextlost', this.handleContextLost);
  621. this.view.removeEventListener('webglcontextrestored', this.handleContextRestored);
  622. this.textureManager.destroy();
  623. // call base destroy
  624. super.destroy(removeView);
  625. this.uid = 0;
  626. // destroy the managers
  627. this.maskManager.destroy();
  628. this.stencilManager.destroy();
  629. this.filterManager.destroy();
  630. this.maskManager = null;
  631. this.filterManager = null;
  632. this.textureManager = null;
  633. this.currentRenderer = null;
  634. this.handleContextLost = null;
  635. this.handleContextRestored = null;
  636. this._contextOptions = null;
  637. this.gl.useProgram(null);
  638. if (this.gl.getExtension('WEBGL_lose_context'))
  639. {
  640. this.gl.getExtension('WEBGL_lose_context').loseContext();
  641. }
  642. this.gl = null;
  643. // this = null;
  644. }
  645. }
  646. /**
  647. * Collection of installed plugins. These are included by default in PIXI, but can be excluded
  648. * by creating a custom build. Consult the README for more information about creating custom
  649. * builds and excluding plugins.
  650. * @name PIXI.WebGLRenderer#plugins
  651. * @type {object}
  652. * @readonly
  653. * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
  654. * @property {PIXI.extract.WebGLExtract} extract Extract image data from renderer.
  655. * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
  656. * @property {PIXI.prepare.WebGLPrepare} prepare Pre-render display objects.
  657. */
  658. /**
  659. * Adds a plugin to the renderer.
  660. *
  661. * @method PIXI.WebGLRenderer#registerPlugin
  662. * @param {string} pluginName - The name of the plugin.
  663. * @param {Function} ctor - The constructor function or class for the plugin.
  664. */
  665. pluginTarget.mixin(WebGLRenderer);