| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930 |
- import Animation from './Animation.js';
- import RenderObjects from './RenderObjects.js';
- import Attributes from './Attributes.js';
- import Geometries from './Geometries.js';
- import Info from './Info.js';
- import Pipelines from './Pipelines.js';
- import Bindings from './Bindings.js';
- import RenderLists from './RenderLists.js';
- import RenderContexts from './RenderContexts.js';
- import Textures from './Textures.js';
- import Background from './Background.js';
- import Nodes from './nodes/Nodes.js';
- import Color4 from './Color4.js';
- import ClippingContext from './ClippingContext.js';
- import QuadMesh from './QuadMesh.js';
- import RenderBundles from './RenderBundles.js';
- import NodeLibrary from './nodes/NodeLibrary.js';
- import Lighting from './Lighting.js';
- import XRManager from './XRManager.js';
- import NodeMaterial from '../../materials/nodes/NodeMaterial.js';
- import { Scene } from '../../scenes/Scene.js';
- import { Frustum } from '../../math/Frustum.js';
- import { Matrix4 } from '../../math/Matrix4.js';
- import { Vector2 } from '../../math/Vector2.js';
- import { Vector4 } from '../../math/Vector4.js';
- import { RenderTarget } from '../../core/RenderTarget.js';
- import { DoubleSide, BackSide, FrontSide, SRGBColorSpace, NoToneMapping, LinearFilter, LinearSRGBColorSpace, HalfFloatType, RGBAFormat, PCFShadowMap } from '../../constants.js';
- const _scene = /*@__PURE__*/ new Scene();
- const _drawingBufferSize = /*@__PURE__*/ new Vector2();
- const _screen = /*@__PURE__*/ new Vector4();
- const _frustum = /*@__PURE__*/ new Frustum();
- const _projScreenMatrix = /*@__PURE__*/ new Matrix4();
- const _vector4 = /*@__PURE__*/ new Vector4();
- /**
- * Base class for renderers.
- */
- class Renderer {
- /**
- * Constructs a new renderer.
- *
- * @param {Backend} backend - The backend the renderer is targeting (e.g. WebGPU or WebGL 2).
- * @param {Object} parameters - The configuration parameter.
- * @param {boolean} [parameters.logarithmicDepthBuffer=false] - Whether logarithmic depth buffer is enabled or not.
- * @param {boolean} [parameters.alpha=true] - Whether the default framebuffer (which represents the final contents of the canvas) should be transparent or opaque.
- * @param {boolean} [parameters.depth=true] - Whether the default framebuffer should have a depth buffer or not.
- * @param {boolean} [parameters.stencil=false] - Whether the default framebuffer should have a stencil buffer or not.
- * @param {boolean} [parameters.antialias=false] - Whether MSAA as the default anti-aliasing should be enabled or not.
- * @param {number} [parameters.samples=0] - When `antialias` is `true`, `4` samples are used by default. This parameter can set to any other integer value than 0
- * to overwrite the default.
- * @param {?Function} [parameters.getFallback=null] - This callback function can be used to provide a fallback backend, if the primary backend can't be targeted.
- * @param {number} [parameters.colorBufferType=HalfFloatType] - Defines the type of color buffers. The default `HalfFloatType` is recommend for best
- * quality. To save memory and bandwidth, `UnsignedByteType` might be used. This will reduce rendering quality though.
- */
- constructor( backend, parameters = {} ) {
- /**
- * This flag can be used for type testing.
- *
- * @type {boolean}
- * @readonly
- * @default true
- */
- this.isRenderer = true;
- //
- const {
- logarithmicDepthBuffer = false,
- alpha = true,
- depth = true,
- stencil = false,
- antialias = false,
- samples = 0,
- getFallback = null,
- colorBufferType = HalfFloatType
- } = parameters;
- /**
- * A reference to the canvas element the renderer is drawing to.
- * This value of this property will automatically be created by
- * the renderer.
- *
- * @type {HTMLCanvasElement|OffscreenCanvas}
- */
- this.domElement = backend.getDomElement();
- /**
- * A reference to the current backend.
- *
- * @type {Backend}
- */
- this.backend = backend;
- /**
- * The number of MSAA samples.
- *
- * @type {number}
- * @default 0
- */
- this.samples = samples || ( antialias === true ) ? 4 : 0;
- /**
- * Whether the renderer should automatically clear the current rendering target
- * before execute a `render()` call. The target can be the canvas (default framebuffer)
- * or the current bound render target (custom framebuffer).
- *
- * @type {boolean}
- * @default true
- */
- this.autoClear = true;
- /**
- * When `autoClear` is set to `true`, this property defines whether the renderer
- * should clear the color buffer.
- *
- * @type {boolean}
- * @default true
- */
- this.autoClearColor = true;
- /**
- * When `autoClear` is set to `true`, this property defines whether the renderer
- * should clear the depth buffer.
- *
- * @type {boolean}
- * @default true
- */
- this.autoClearDepth = true;
- /**
- * When `autoClear` is set to `true`, this property defines whether the renderer
- * should clear the stencil buffer.
- *
- * @type {boolean}
- * @default true
- */
- this.autoClearStencil = true;
- /**
- * Whether the default framebuffer should be transparent or opaque.
- *
- * @type {boolean}
- * @default true
- */
- this.alpha = alpha;
- /**
- * Whether logarithmic depth buffer is enabled or not.
- *
- * @type {boolean}
- * @default false
- */
- this.logarithmicDepthBuffer = logarithmicDepthBuffer;
- /**
- * Defines the output color space of the renderer.
- *
- * @type {string}
- * @default SRGBColorSpace
- */
- this.outputColorSpace = SRGBColorSpace;
- /**
- * Defines the tone mapping of the renderer.
- *
- * @type {number}
- * @default NoToneMapping
- */
- this.toneMapping = NoToneMapping;
- /**
- * Defines the tone mapping exposure.
- *
- * @type {number}
- * @default 1
- */
- this.toneMappingExposure = 1.0;
- /**
- * Whether the renderer should sort its render lists or not.
- *
- * Note: Sorting is used to attempt to properly render objects that have some degree of transparency.
- * By definition, sorting objects may not work in all cases. Depending on the needs of application,
- * it may be necessary to turn off sorting and use other methods to deal with transparency rendering
- * e.g. manually determining each object's rendering order.
- *
- * @type {boolean}
- * @default true
- */
- this.sortObjects = true;
- /**
- * Whether the default framebuffer should have a depth buffer or not.
- *
- * @type {boolean}
- * @default true
- */
- this.depth = depth;
- /**
- * Whether the default framebuffer should have a stencil buffer or not.
- *
- * @type {boolean}
- * @default false
- */
- this.stencil = stencil;
- /**
- * Holds a series of statistical information about the GPU memory
- * and the rendering process. Useful for debugging and monitoring.
- *
- * @type {Info}
- */
- this.info = new Info();
- this.nodes = {
- modelViewMatrix: null,
- modelNormalViewMatrix: null
- };
- /**
- * The node library defines how certain library objects like materials, lights
- * or tone mapping functions are mapped to node types. This is required since
- * although instances of classes like `MeshBasicMaterial` or `PointLight` can
- * be part of the scene graph, they are internally represented as nodes for
- * further processing.
- *
- * @type {NodeLibrary}
- */
- this.library = new NodeLibrary();
- /**
- * A map-like data structure for managing lights.
- *
- * @type {Lighting}
- */
- this.lighting = new Lighting();
- // internals
- /**
- * This callback function can be used to provide a fallback backend, if the primary backend can't be targeted.
- *
- * @private
- * @type {Function}
- */
- this._getFallback = getFallback;
- /**
- * The renderer's pixel ration.
- *
- * @private
- * @type {number}
- * @default 1
- */
- this._pixelRatio = 1;
- /**
- * The width of the renderer's default framebuffer in logical pixel unit.
- *
- * @private
- * @type {number}
- */
- this._width = this.domElement.width;
- /**
- * The height of the renderer's default framebuffer in logical pixel unit.
- *
- * @private
- * @type {number}
- */
- this._height = this.domElement.height;
- /**
- * The viewport of the renderer in logical pixel unit.
- *
- * @private
- * @type {Vector4}
- */
- this._viewport = new Vector4( 0, 0, this._width, this._height );
- /**
- * The scissor rectangle of the renderer in logical pixel unit.
- *
- * @private
- * @type {Vector4}
- */
- this._scissor = new Vector4( 0, 0, this._width, this._height );
- /**
- * Whether the scissor test should be enabled or not.
- *
- * @private
- * @type {boolean}
- */
- this._scissorTest = false;
- /**
- * A reference to a renderer module for managing shader attributes.
- *
- * @private
- * @type {?Attributes}
- * @default null
- */
- this._attributes = null;
- /**
- * A reference to a renderer module for managing geometries.
- *
- * @private
- * @type {?Geometries}
- * @default null
- */
- this._geometries = null;
- /**
- * A reference to a renderer module for managing node related logic.
- *
- * @private
- * @type {?Nodes}
- * @default null
- */
- this._nodes = null;
- /**
- * A reference to a renderer module for managing the internal animation loop.
- *
- * @private
- * @type {?Animation}
- * @default null
- */
- this._animation = null;
- /**
- * A reference to a renderer module for managing shader program bindings.
- *
- * @private
- * @type {?Bindings}
- * @default null
- */
- this._bindings = null;
- /**
- * A reference to a renderer module for managing render objects.
- *
- * @private
- * @type {?RenderObjects}
- * @default null
- */
- this._objects = null;
- /**
- * A reference to a renderer module for managing render and compute pipelines.
- *
- * @private
- * @type {?Pipelines}
- * @default null
- */
- this._pipelines = null;
- /**
- * A reference to a renderer module for managing render bundles.
- *
- * @private
- * @type {?RenderBundles}
- * @default null
- */
- this._bundles = null;
- /**
- * A reference to a renderer module for managing render lists.
- *
- * @private
- * @type {?RenderLists}
- * @default null
- */
- this._renderLists = null;
- /**
- * A reference to a renderer module for managing render contexts.
- *
- * @private
- * @type {?RenderContexts}
- * @default null
- */
- this._renderContexts = null;
- /**
- * A reference to a renderer module for managing textures.
- *
- * @private
- * @type {?Textures}
- * @default null
- */
- this._textures = null;
- /**
- * A reference to a renderer module for backgrounds.
- *
- * @private
- * @type {?Background}
- * @default null
- */
- this._background = null;
- /**
- * This fullscreen quad is used for internal render passes
- * like the tone mapping and color space output pass.
- *
- * @private
- * @type {QuadMesh}
- */
- this._quad = new QuadMesh( new NodeMaterial() );
- this._quad.material.name = 'Renderer_output';
- /**
- * A reference to the current render context.
- *
- * @private
- * @type {?RenderContext}
- * @default null
- */
- this._currentRenderContext = null;
- /**
- * A custom sort function for the opaque render list.
- *
- * @private
- * @type {?Function}
- * @default null
- */
- this._opaqueSort = null;
- /**
- * A custom sort function for the transparent render list.
- *
- * @private
- * @type {?Function}
- * @default null
- */
- this._transparentSort = null;
- /**
- * The framebuffer target.
- *
- * @private
- * @type {?RenderTarget}
- * @default null
- */
- this._frameBufferTarget = null;
- const alphaClear = this.alpha === true ? 0 : 1;
- /**
- * The clear color value.
- *
- * @private
- * @type {Color4}
- */
- this._clearColor = new Color4( 0, 0, 0, alphaClear );
- /**
- * The clear depth value.
- *
- * @private
- * @type {number}
- * @default 1
- */
- this._clearDepth = 1;
- /**
- * The clear stencil value.
- *
- * @private
- * @type {number}
- * @default 0
- */
- this._clearStencil = 0;
- /**
- * The current render target.
- *
- * @private
- * @type {?RenderTarget}
- * @default null
- */
- this._renderTarget = null;
- /**
- * The active cube face.
- *
- * @private
- * @type {number}
- * @default 0
- */
- this._activeCubeFace = 0;
- /**
- * The active mipmap level.
- *
- * @private
- * @type {number}
- * @default 0
- */
- this._activeMipmapLevel = 0;
- /**
- * The current output render target.
- *
- * @private
- * @type {?RenderTarget}
- * @default null
- */
- this._outputRenderTarget = null;
- /**
- * The MRT setting.
- *
- * @private
- * @type {?MRTNode}
- * @default null
- */
- this._mrt = null;
- /**
- * This function defines how a render object is going
- * to be rendered.
- *
- * @private
- * @type {?Function}
- * @default null
- */
- this._renderObjectFunction = null;
- /**
- * Used to keep track of the current render object function.
- *
- * @private
- * @type {?Function}
- * @default null
- */
- this._currentRenderObjectFunction = null;
- /**
- * Used to keep track of the current render bundle.
- *
- * @private
- * @type {?RenderBundle}
- * @default null
- */
- this._currentRenderBundle = null;
- /**
- * Next to `_renderObjectFunction()`, this function provides another hook
- * for influencing the render process of a render object. It is meant for internal
- * use and only relevant for `compileAsync()` right now. Instead of using
- * the default logic of `_renderObjectDirect()` which actually draws the render object,
- * a different function might be used which performs no draw but just the node
- * and pipeline updates.
- *
- * @private
- * @type {?Function}
- * @default null
- */
- this._handleObjectFunction = this._renderObjectDirect;
- /**
- * Indicates whether the device has been lost or not. In WebGL terms, the device
- * lost is considered as a context lost. When this is set to `true`, rendering
- * isn't possible anymore.
- *
- * @private
- * @type {boolean}
- * @default false
- */
- this._isDeviceLost = false;
- /**
- * A callback function that defines what should happen when a device/context lost occurs.
- *
- * @type {Function}
- */
- this.onDeviceLost = this._onDeviceLost;
- /**
- * Defines the type of color buffers. The default `HalfFloatType` is recommend for
- * best quality. To save memory and bandwidth, `UnsignedByteType` might be used.
- * This will reduce rendering quality though.
- *
- * @private
- * @type {number}
- * @default HalfFloatType
- */
- this._colorBufferType = colorBufferType;
- /**
- * Whether the renderer has been initialized or not.
- *
- * @private
- * @type {boolean}
- * @default false
- */
- this._initialized = false;
- /**
- * A reference to the promise which initializes the renderer.
- *
- * @private
- * @type {?Promise}
- * @default null
- */
- this._initPromise = null;
- /**
- * An array of compilation promises which are used in `compileAsync()`.
- *
- * @private
- * @type {?Array<Promise>}
- * @default null
- */
- this._compilationPromises = null;
- /**
- * Whether the renderer should render transparent render objects or not.
- *
- * @type {boolean}
- * @default true
- */
- this.transparent = true;
- /**
- * Whether the renderer should render opaque render objects or not.
- *
- * @type {boolean}
- * @default true
- */
- this.opaque = true;
- /**
- * Shadow map configuration
- * @typedef {Object} ShadowMapConfig
- * @property {boolean} enabled - Whether to globally enable shadows or not.
- * @property {number} type - The shadow map type.
- */
- /**
- * The renderer's shadow configuration.
- *
- * @type {ShadowMapConfig}
- */
- this.shadowMap = {
- enabled: false,
- type: PCFShadowMap
- };
- /**
- * XR configuration.
- * @typedef {Object} XRConfig
- * @property {boolean} enabled - Whether to globally enable XR or not.
- */
- /**
- * The renderer's XR manager.
- *
- * @type {XRManager}
- */
- this.xr = new XRManager( this );
- /**
- * Debug configuration.
- * @typedef {Object} DebugConfig
- * @property {boolean} checkShaderErrors - Whether shader errors should be checked or not.
- * @property {Function} onShaderError - A callback function that is executed when a shader error happens. Only supported with WebGL 2 right now.
- * @property {Function} getShaderAsync - Allows the get the raw shader code for the given scene, camera and 3D object.
- */
- /**
- * The renderer's debug configuration.
- *
- * @type {DebugConfig}
- */
- this.debug = {
- checkShaderErrors: true,
- onShaderError: null,
- getShaderAsync: async ( scene, camera, object ) => {
- await this.compileAsync( scene, camera );
- const renderList = this._renderLists.get( scene, camera );
- const renderContext = this._renderContexts.get( scene, camera, this._renderTarget );
- const material = scene.overrideMaterial || object.material;
- const renderObject = this._objects.get( object, material, scene, camera, renderList.lightsNode, renderContext, renderContext.clippingContext );
- const { fragmentShader, vertexShader } = renderObject.getNodeBuilderState();
- return { fragmentShader, vertexShader };
- }
- };
- }
- /**
- * Initializes the renderer so it is ready for usage.
- *
- * @async
- * @return {Promise} A Promise that resolves when the renderer has been initialized.
- */
- async init() {
- if ( this._initialized ) {
- throw new Error( 'Renderer: Backend has already been initialized.' );
- }
- if ( this._initPromise !== null ) {
- return this._initPromise;
- }
- this._initPromise = new Promise( async ( resolve, reject ) => {
- let backend = this.backend;
- try {
- await backend.init( this );
- } catch ( error ) {
- if ( this._getFallback !== null ) {
- // try the fallback
- try {
- this.backend = backend = this._getFallback( error );
- await backend.init( this );
- } catch ( error ) {
- reject( error );
- return;
- }
- } else {
- reject( error );
- return;
- }
- }
- this._nodes = new Nodes( this, backend );
- this._animation = new Animation( this._nodes, this.info );
- this._attributes = new Attributes( backend );
- this._background = new Background( this, this._nodes );
- this._geometries = new Geometries( this._attributes, this.info );
- this._textures = new Textures( this, backend, this.info );
- this._pipelines = new Pipelines( backend, this._nodes );
- this._bindings = new Bindings( backend, this._nodes, this._textures, this._attributes, this._pipelines, this.info );
- this._objects = new RenderObjects( this, this._nodes, this._geometries, this._pipelines, this._bindings, this.info );
- this._renderLists = new RenderLists( this.lighting );
- this._bundles = new RenderBundles();
- this._renderContexts = new RenderContexts();
- //
- this._animation.start();
- this._initialized = true;
- resolve();
- } );
- return this._initPromise;
- }
- /**
- * The coordinate system of the renderer. The value of this property
- * depends on the selected backend. Either `THREE.WebGLCoordinateSystem` or
- * `THREE.WebGPUCoordinateSystem`.
- *
- * @readonly
- * @type {number}
- */
- get coordinateSystem() {
- return this.backend.coordinateSystem;
- }
- /**
- * Compiles all materials in the given scene. This can be useful to avoid a
- * phenomenon which is called "shader compilation stutter", which occurs when
- * rendering an object with a new shader for the first time.
- *
- * If you want to add a 3D object to an existing scene, use the third optional
- * parameter for applying the target scene. Note that the (target) scene's lighting
- * and environment must be configured before calling this method.
- *
- * @async
- * @param {Object3D} scene - The scene or 3D object to precompile.
- * @param {Camera} camera - The camera that is used to render the scene.
- * @param {Scene} targetScene - If the first argument is a 3D object, this parameter must represent the scene the 3D object is going to be added.
- * @return {Promise<Array>} A Promise that resolves when the compile has been finished.
- */
- async compileAsync( scene, camera, targetScene = null ) {
- if ( this._isDeviceLost === true ) return;
- if ( this._initialized === false ) await this.init();
- // preserve render tree
- const nodeFrame = this._nodes.nodeFrame;
- const previousRenderId = nodeFrame.renderId;
- const previousRenderContext = this._currentRenderContext;
- const previousRenderObjectFunction = this._currentRenderObjectFunction;
- const previousCompilationPromises = this._compilationPromises;
- //
- const sceneRef = ( scene.isScene === true ) ? scene : _scene;
- if ( targetScene === null ) targetScene = scene;
- const renderTarget = this._renderTarget;
- const renderContext = this._renderContexts.get( targetScene, camera, renderTarget );
- const activeMipmapLevel = this._activeMipmapLevel;
- const compilationPromises = [];
- this._currentRenderContext = renderContext;
- this._currentRenderObjectFunction = this.renderObject;
- this._handleObjectFunction = this._createObjectPipeline;
- this._compilationPromises = compilationPromises;
- nodeFrame.renderId ++;
- //
- nodeFrame.update();
- //
- renderContext.depth = this.depth;
- renderContext.stencil = this.stencil;
- if ( ! renderContext.clippingContext ) renderContext.clippingContext = new ClippingContext();
- renderContext.clippingContext.updateGlobal( sceneRef, camera );
- //
- sceneRef.onBeforeRender( this, scene, camera, renderTarget );
- //
- const renderList = this._renderLists.get( scene, camera );
- renderList.begin();
- this._projectObject( scene, camera, 0, renderList, renderContext.clippingContext );
- // include lights from target scene
- if ( targetScene !== scene ) {
- targetScene.traverseVisible( function ( object ) {
- if ( object.isLight && object.layers.test( camera.layers ) ) {
- renderList.pushLight( object );
- }
- } );
- }
- renderList.finish();
- //
- if ( renderTarget !== null ) {
- this._textures.updateRenderTarget( renderTarget, activeMipmapLevel );
- const renderTargetData = this._textures.get( renderTarget );
- renderContext.textures = renderTargetData.textures;
- renderContext.depthTexture = renderTargetData.depthTexture;
- } else {
- renderContext.textures = null;
- renderContext.depthTexture = null;
- }
- //
- this._background.update( sceneRef, renderList, renderContext );
- // process render lists
- const opaqueObjects = renderList.opaque;
- const transparentObjects = renderList.transparent;
- const transparentDoublePassObjects = renderList.transparentDoublePass;
- const lightsNode = renderList.lightsNode;
- if ( this.opaque === true && opaqueObjects.length > 0 ) this._renderObjects( opaqueObjects, camera, sceneRef, lightsNode );
- if ( this.transparent === true && transparentObjects.length > 0 ) this._renderTransparents( transparentObjects, transparentDoublePassObjects, camera, sceneRef, lightsNode );
- // restore render tree
- nodeFrame.renderId = previousRenderId;
- this._currentRenderContext = previousRenderContext;
- this._currentRenderObjectFunction = previousRenderObjectFunction;
- this._compilationPromises = previousCompilationPromises;
- this._handleObjectFunction = this._renderObjectDirect;
- // wait for all promises setup by backends awaiting compilation/linking/pipeline creation to complete
- await Promise.all( compilationPromises );
- }
- /**
- * Renders the scene in an async fashion.
- *
- * @async
- * @param {Object3D} scene - The scene or 3D object to render.
- * @param {Camera} camera - The camera.
- * @return {Promise} A Promise that resolves when the render has been finished.
- */
- async renderAsync( scene, camera ) {
- if ( this._initialized === false ) await this.init();
- this._renderScene( scene, camera );
- }
- /**
- * Can be used to synchronize CPU operations with GPU tasks. So when this method is called,
- * the CPU waits for the GPU to complete its operation (e.g. a compute task).
- *
- * @async
- * @return {Promise} A Promise that resolves when synchronization has been finished.
- */
- async waitForGPU() {
- await this.backend.waitForGPU();
- }
- /**
- * Sets the given MRT configuration.
- *
- * @param {MRTNode} mrt - The MRT node to set.
- * @return {Renderer} A reference to this renderer.
- */
- setMRT( mrt ) {
- this._mrt = mrt;
- return this;
- }
- /**
- * Returns the MRT configuration.
- *
- * @return {MRTNode} The MRT configuration.
- */
- getMRT() {
- return this._mrt;
- }
- /**
- * Returns the color buffer type.
- *
- * @return {number} The color buffer type.
- */
- getColorBufferType() {
- return this._colorBufferType;
- }
- /**
- * Default implementation of the device lost callback.
- *
- * @private
- * @param {Object} info - Information about the context lost.
- */
- _onDeviceLost( info ) {
- let errorMessage = `THREE.WebGPURenderer: ${info.api} Device Lost:\n\nMessage: ${info.message}`;
- if ( info.reason ) {
- errorMessage += `\nReason: ${info.reason}`;
- }
- console.error( errorMessage );
- this._isDeviceLost = true;
- }
- /**
- * Renders the given render bundle.
- *
- * @private
- * @param {Object} bundle - Render bundle data.
- * @param {Scene} sceneRef - The scene the render bundle belongs to.
- * @param {LightsNode} lightsNode - The current lights node.
- */
- _renderBundle( bundle, sceneRef, lightsNode ) {
- const { bundleGroup, camera, renderList } = bundle;
- const renderContext = this._currentRenderContext;
- //
- const renderBundle = this._bundles.get( bundleGroup, camera );
- const renderBundleData = this.backend.get( renderBundle );
- if ( renderBundleData.renderContexts === undefined ) renderBundleData.renderContexts = new Set();
- //
- const needsUpdate = bundleGroup.version !== renderBundleData.version;
- const renderBundleNeedsUpdate = renderBundleData.renderContexts.has( renderContext ) === false || needsUpdate;
- renderBundleData.renderContexts.add( renderContext );
- if ( renderBundleNeedsUpdate ) {
- this.backend.beginBundle( renderContext );
- if ( renderBundleData.renderObjects === undefined || needsUpdate ) {
- renderBundleData.renderObjects = [];
- }
- this._currentRenderBundle = renderBundle;
- const opaqueObjects = renderList.opaque;
- if ( this.opaque === true && opaqueObjects.length > 0 ) this._renderObjects( opaqueObjects, camera, sceneRef, lightsNode );
- this._currentRenderBundle = null;
- //
- this.backend.finishBundle( renderContext, renderBundle );
- renderBundleData.version = bundleGroup.version;
- } else {
- const { renderObjects } = renderBundleData;
- for ( let i = 0, l = renderObjects.length; i < l; i ++ ) {
- const renderObject = renderObjects[ i ];
- if ( this._nodes.needsRefresh( renderObject ) ) {
- this._nodes.updateBefore( renderObject );
- this._nodes.updateForRender( renderObject );
- this._bindings.updateForRender( renderObject );
- this._nodes.updateAfter( renderObject );
- }
- }
- }
- this.backend.addBundle( renderContext, renderBundle );
- }
- /**
- * Renders the scene or 3D object with the given camera. This method can only be called
- * if the renderer has been initialized.
- *
- * The target of the method is the default framebuffer (meaning the canvas)
- * or alternatively a render target when specified via `setRenderTarget()`.
- *
- * @param {Object3D} scene - The scene or 3D object to render.
- * @param {Camera} camera - The camera to render the scene with.
- * @return {?Promise} A Promise that resolve when the scene has been rendered.
- * Only returned when the renderer has not been initialized.
- */
- render( scene, camera ) {
- if ( this._initialized === false ) {
- console.warn( 'THREE.Renderer: .render() called before the backend is initialized. Try using .renderAsync() instead.' );
- return this.renderAsync( scene, camera );
- }
- this._renderScene( scene, camera );
- }
- /**
- * Returns an internal render target which is used when computing the output tone mapping
- * and color space conversion. Unlike in `WebGLRenderer`, this is done in a separate render
- * pass and not inline to achieve more correct results.
- *
- * @private
- * @return {?RenderTarget} The render target. The method returns `null` if no output conversion should be applied.
- */
- _getFrameBufferTarget() {
- const { currentToneMapping, currentColorSpace } = this;
- const useToneMapping = currentToneMapping !== NoToneMapping;
- const useColorSpace = currentColorSpace !== LinearSRGBColorSpace;
- if ( useToneMapping === false && useColorSpace === false ) return null;
- const { width, height } = this.getDrawingBufferSize( _drawingBufferSize );
- const { depth, stencil } = this;
- let frameBufferTarget = this._frameBufferTarget;
- if ( frameBufferTarget === null ) {
- frameBufferTarget = new RenderTarget( width, height, {
- depthBuffer: depth,
- stencilBuffer: stencil,
- type: this._colorBufferType,
- format: RGBAFormat,
- colorSpace: LinearSRGBColorSpace,
- generateMipmaps: false,
- minFilter: LinearFilter,
- magFilter: LinearFilter,
- samples: this.samples
- } );
- frameBufferTarget.isPostProcessingRenderTarget = true;
- this._frameBufferTarget = frameBufferTarget;
- }
- frameBufferTarget.depthBuffer = depth;
- frameBufferTarget.stencilBuffer = stencil;
- frameBufferTarget.setSize( width, height );
- frameBufferTarget.viewport.copy( this._viewport );
- frameBufferTarget.scissor.copy( this._scissor );
- frameBufferTarget.viewport.multiplyScalar( this._pixelRatio );
- frameBufferTarget.scissor.multiplyScalar( this._pixelRatio );
- frameBufferTarget.scissorTest = this._scissorTest;
- return frameBufferTarget;
- }
- /**
- * Renders the scene or 3D object with the given camera.
- *
- * @private
- * @param {Object3D} scene - The scene or 3D object to render.
- * @param {Camera} camera - The camera to render the scene with.
- * @param {boolean} [useFrameBufferTarget=true] - Whether to use a framebuffer target or not.
- * @return {RenderContext} The current render context.
- */
- _renderScene( scene, camera, useFrameBufferTarget = true ) {
- if ( this._isDeviceLost === true ) return;
- const frameBufferTarget = useFrameBufferTarget ? this._getFrameBufferTarget() : null;
- // preserve render tree
- const nodeFrame = this._nodes.nodeFrame;
- const previousRenderId = nodeFrame.renderId;
- const previousRenderContext = this._currentRenderContext;
- const previousRenderObjectFunction = this._currentRenderObjectFunction;
- //
- const sceneRef = ( scene.isScene === true ) ? scene : _scene;
- const outputRenderTarget = this._renderTarget || this._outputRenderTarget;
- const activeCubeFace = this._activeCubeFace;
- const activeMipmapLevel = this._activeMipmapLevel;
- //
- let renderTarget;
- if ( frameBufferTarget !== null ) {
- renderTarget = frameBufferTarget;
- this.setRenderTarget( renderTarget );
- } else {
- renderTarget = outputRenderTarget;
- }
- //
- const renderContext = this._renderContexts.get( scene, camera, renderTarget );
- this._currentRenderContext = renderContext;
- this._currentRenderObjectFunction = this._renderObjectFunction || this.renderObject;
- //
- this.info.calls ++;
- this.info.render.calls ++;
- this.info.render.frameCalls ++;
- nodeFrame.renderId = this.info.calls;
- //
- const coordinateSystem = this.coordinateSystem;
- const xr = this.xr;
- if ( camera.coordinateSystem !== coordinateSystem && xr.isPresenting === false ) {
- camera.coordinateSystem = coordinateSystem;
- camera.updateProjectionMatrix();
- if ( camera.isArrayCamera ) {
- for ( const subCamera of camera.cameras ) {
- subCamera.coordinateSystem = coordinateSystem;
- subCamera.updateProjectionMatrix();
- }
- }
- }
- //
- if ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld();
- if ( camera.parent === null && camera.matrixWorldAutoUpdate === true ) camera.updateMatrixWorld();
- if ( xr.enabled === true && xr.isPresenting === true ) {
- if ( xr.cameraAutoUpdate === true ) xr.updateCamera( camera );
- camera = xr.getCamera(); // use XR camera for rendering
- }
- //
- let viewport = this._viewport;
- let scissor = this._scissor;
- let pixelRatio = this._pixelRatio;
- if ( renderTarget !== null ) {
- viewport = renderTarget.viewport;
- scissor = renderTarget.scissor;
- pixelRatio = 1;
- }
- this.getDrawingBufferSize( _drawingBufferSize );
- _screen.set( 0, 0, _drawingBufferSize.width, _drawingBufferSize.height );
- const minDepth = ( viewport.minDepth === undefined ) ? 0 : viewport.minDepth;
- const maxDepth = ( viewport.maxDepth === undefined ) ? 1 : viewport.maxDepth;
- renderContext.viewportValue.copy( viewport ).multiplyScalar( pixelRatio ).floor();
- renderContext.viewportValue.width >>= activeMipmapLevel;
- renderContext.viewportValue.height >>= activeMipmapLevel;
- renderContext.viewportValue.minDepth = minDepth;
- renderContext.viewportValue.maxDepth = maxDepth;
- renderContext.viewport = renderContext.viewportValue.equals( _screen ) === false;
- renderContext.scissorValue.copy( scissor ).multiplyScalar( pixelRatio ).floor();
- renderContext.scissor = this._scissorTest && renderContext.scissorValue.equals( _screen ) === false;
- renderContext.scissorValue.width >>= activeMipmapLevel;
- renderContext.scissorValue.height >>= activeMipmapLevel;
- if ( ! renderContext.clippingContext ) renderContext.clippingContext = new ClippingContext();
- renderContext.clippingContext.updateGlobal( sceneRef, camera );
- //
- sceneRef.onBeforeRender( this, scene, camera, renderTarget );
- //
- _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
- _frustum.setFromProjectionMatrix( _projScreenMatrix, coordinateSystem );
- const renderList = this._renderLists.get( scene, camera );
- renderList.begin();
- this._projectObject( scene, camera, 0, renderList, renderContext.clippingContext );
- renderList.finish();
- if ( this.sortObjects === true ) {
- renderList.sort( this._opaqueSort, this._transparentSort );
- }
- //
- if ( renderTarget !== null ) {
- this._textures.updateRenderTarget( renderTarget, activeMipmapLevel );
- const renderTargetData = this._textures.get( renderTarget );
- renderContext.textures = renderTargetData.textures;
- renderContext.depthTexture = renderTargetData.depthTexture;
- renderContext.width = renderTargetData.width;
- renderContext.height = renderTargetData.height;
- renderContext.renderTarget = renderTarget;
- renderContext.depth = renderTarget.depthBuffer;
- renderContext.stencil = renderTarget.stencilBuffer;
- } else {
- renderContext.textures = null;
- renderContext.depthTexture = null;
- renderContext.width = this.domElement.width;
- renderContext.height = this.domElement.height;
- renderContext.depth = this.depth;
- renderContext.stencil = this.stencil;
- }
- renderContext.width >>= activeMipmapLevel;
- renderContext.height >>= activeMipmapLevel;
- renderContext.activeCubeFace = activeCubeFace;
- renderContext.activeMipmapLevel = activeMipmapLevel;
- renderContext.occlusionQueryCount = renderList.occlusionQueryCount;
- //
- this._background.update( sceneRef, renderList, renderContext );
- //
- this.backend.beginRender( renderContext );
- // process render lists
- const {
- bundles,
- lightsNode,
- transparentDoublePass: transparentDoublePassObjects,
- transparent: transparentObjects,
- opaque: opaqueObjects
- } = renderList;
- if ( bundles.length > 0 ) this._renderBundles( bundles, sceneRef, lightsNode );
- if ( this.opaque === true && opaqueObjects.length > 0 ) this._renderObjects( opaqueObjects, camera, sceneRef, lightsNode );
- if ( this.transparent === true && transparentObjects.length > 0 ) this._renderTransparents( transparentObjects, transparentDoublePassObjects, camera, sceneRef, lightsNode );
- // finish render pass
- this.backend.finishRender( renderContext );
- // restore render tree
- nodeFrame.renderId = previousRenderId;
- this._currentRenderContext = previousRenderContext;
- this._currentRenderObjectFunction = previousRenderObjectFunction;
- //
- if ( frameBufferTarget !== null ) {
- this.setRenderTarget( outputRenderTarget, activeCubeFace, activeMipmapLevel );
- this._renderOutput( renderTarget );
- }
- //
- sceneRef.onAfterRender( this, scene, camera, renderTarget );
- //
- return renderContext;
- }
- /**
- * The output pass performs tone mapping and color space conversion.
- *
- * @private
- * @param {RenderTarget} renderTarget - The current render target.
- */
- _renderOutput( renderTarget ) {
- const quad = this._quad;
- if ( this._nodes.hasOutputChange( renderTarget.texture ) ) {
- quad.material.fragmentNode = this._nodes.getOutputNode( renderTarget.texture );
- quad.material.needsUpdate = true;
- }
- // a clear operation clears the intermediate renderTarget texture, but should not update the screen canvas.
- const currentAutoClear = this.autoClear;
- const currentXR = this.xr.enabled;
- this.autoClear = false;
- this.xr.enabled = false;
- this._renderScene( quad, quad.camera, false );
- this.autoClear = currentAutoClear;
- this.xr.enabled = currentXR;
- }
- /**
- * Returns the maximum available anisotropy for texture filtering.
- *
- * @return {number} The maximum available anisotropy.
- */
- getMaxAnisotropy() {
- return this.backend.getMaxAnisotropy();
- }
- /**
- * Returns the active cube face.
- *
- * @return {number} The active cube face.
- */
- getActiveCubeFace() {
- return this._activeCubeFace;
- }
- /**
- * Returns the active mipmap level.
- *
- * @return {number} The active mipmap level.
- */
- getActiveMipmapLevel() {
- return this._activeMipmapLevel;
- }
- /**
- * Applications are advised to always define the animation loop
- * with this method and not manually with `requestAnimationFrame()`
- * for best compatibility.
- *
- * @async
- * @param {Function} callback - The application's animation loop.
- * @return {Promise} A Promise that resolves when the set has been executed.
- */
- async setAnimationLoop( callback ) {
- if ( this._initialized === false ) await this.init();
- this._animation.setAnimationLoop( callback );
- }
- /**
- * Can be used to transfer buffer data from a storage buffer attribute
- * from the GPU to the CPU in context of compute shaders.
- *
- * @async
- * @param {StorageBufferAttribute} attribute - The storage buffer attribute.
- * @return {Promise<ArrayBuffer>} A promise that resolves with the buffer data when the data are ready.
- */
- async getArrayBufferAsync( attribute ) {
- return await this.backend.getArrayBufferAsync( attribute );
- }
- /**
- * Returns the rendering context.
- *
- * @return {GPUCanvasContext|WebGL2RenderingContext} The rendering context.
- */
- getContext() {
- return this.backend.getContext();
- }
- /**
- * Returns the pixel ratio.
- *
- * @return {number} The pixel ratio.
- */
- getPixelRatio() {
- return this._pixelRatio;
- }
- /**
- * Returns the drawing buffer size in physical pixels. This method honors the pixel ratio.
- *
- * @param {Vector2} target - The method writes the result in this target object.
- * @return {Vector2} The drawing buffer size.
- */
- getDrawingBufferSize( target ) {
- return target.set( this._width * this._pixelRatio, this._height * this._pixelRatio ).floor();
- }
- /**
- * Returns the renderer's size in logical pixels. This method does not honor the pixel ratio.
- *
- * @param {Vector2} target - The method writes the result in this target object.
- * @return {Vector2} The drawing buffer size.
- */
- getSize( target ) {
- return target.set( this._width, this._height );
- }
- /**
- * Sets the given pixel ration and resizes the canvas if necessary.
- *
- * @param {number} [value=1] - The pixel ratio.
- */
- setPixelRatio( value = 1 ) {
- if ( this._pixelRatio === value ) return;
- this._pixelRatio = value;
- this.setSize( this._width, this._height, false );
- }
- /**
- * This method allows to define the drawing buffer size by specifying
- * width, height and pixel ratio all at once. The size of the drawing
- * buffer is computed with this formula:
- * ````
- * size.x = width * pixelRatio;
- * size.y = height * pixelRatio;
- *```
- *
- * @param {number} width - The width in logical pixels.
- * @param {number} height - The height in logical pixels.
- * @param {number} pixelRatio - The pixel ratio.
- */
- setDrawingBufferSize( width, height, pixelRatio ) {
- this._width = width;
- this._height = height;
- this._pixelRatio = pixelRatio;
- this.domElement.width = Math.floor( width * pixelRatio );
- this.domElement.height = Math.floor( height * pixelRatio );
- this.setViewport( 0, 0, width, height );
- if ( this._initialized ) this.backend.updateSize();
- }
- /**
- * Sets the size of the renderer.
- *
- * @param {number} width - The width in logical pixels.
- * @param {number} height - The height in logical pixels.
- * @param {boolean} [updateStyle=true] - Whether to update the `style` attribute of the canvas or not.
- */
- setSize( width, height, updateStyle = true ) {
- this._width = width;
- this._height = height;
- this.domElement.width = Math.floor( width * this._pixelRatio );
- this.domElement.height = Math.floor( height * this._pixelRatio );
- if ( updateStyle === true ) {
- this.domElement.style.width = width + 'px';
- this.domElement.style.height = height + 'px';
- }
- this.setViewport( 0, 0, width, height );
- if ( this._initialized ) this.backend.updateSize();
- }
- /**
- * Defines a manual sort function for the opaque render list.
- * Pass `null` to use the default sort.
- *
- * @param {Function} method - The sort function.
- */
- setOpaqueSort( method ) {
- this._opaqueSort = method;
- }
- /**
- * Defines a manual sort function for the transparent render list.
- * Pass `null` to use the default sort.
- *
- * @param {Function} method - The sort function.
- */
- setTransparentSort( method ) {
- this._transparentSort = method;
- }
- /**
- * Returns the scissor rectangle.
- *
- * @param {Vector4} target - The method writes the result in this target object.
- * @return {Vector4} The scissor rectangle.
- */
- getScissor( target ) {
- const scissor = this._scissor;
- target.x = scissor.x;
- target.y = scissor.y;
- target.width = scissor.width;
- target.height = scissor.height;
- return target;
- }
- /**
- * Defines the scissor rectangle.
- *
- * @param {number | Vector4} x - The horizontal coordinate for the lower left corner of the box in logical pixel unit.
- * Instead of passing four arguments, the method also works with a single four-dimensional vector.
- * @param {number} y - The vertical coordinate for the lower left corner of the box in logical pixel unit.
- * @param {number} width - The width of the scissor box in logical pixel unit.
- * @param {number} height - The height of the scissor box in logical pixel unit.
- */
- setScissor( x, y, width, height ) {
- const scissor = this._scissor;
- if ( x.isVector4 ) {
- scissor.copy( x );
- } else {
- scissor.set( x, y, width, height );
- }
- }
- /**
- * Returns the scissor test value.
- *
- * @return {boolean} Whether the scissor test should be enabled or not.
- */
- getScissorTest() {
- return this._scissorTest;
- }
- /**
- * Defines the scissor test.
- *
- * @param {boolean} boolean - Whether the scissor test should be enabled or not.
- */
- setScissorTest( boolean ) {
- this._scissorTest = boolean;
- this.backend.setScissorTest( boolean );
- }
- /**
- * Returns the viewport definition.
- *
- * @param {Vector4} target - The method writes the result in this target object.
- * @return {Vector4} The viewport definition.
- */
- getViewport( target ) {
- return target.copy( this._viewport );
- }
- /**
- * Defines the viewport.
- *
- * @param {number | Vector4} x - The horizontal coordinate for the lower left corner of the viewport origin in logical pixel unit.
- * @param {number} y - The vertical coordinate for the lower left corner of the viewport origin in logical pixel unit.
- * @param {number} width - The width of the viewport in logical pixel unit.
- * @param {number} height - The height of the viewport in logical pixel unit.
- * @param {number} minDepth - The minimum depth value of the viewport. WebGPU only.
- * @param {number} maxDepth - The maximum depth value of the viewport. WebGPU only.
- */
- setViewport( x, y, width, height, minDepth = 0, maxDepth = 1 ) {
- const viewport = this._viewport;
- if ( x.isVector4 ) {
- viewport.copy( x );
- } else {
- viewport.set( x, y, width, height );
- }
- viewport.minDepth = minDepth;
- viewport.maxDepth = maxDepth;
- }
- /**
- * Returns the clear color.
- *
- * @param {Color} target - The method writes the result in this target object.
- * @return {Color} The clear color.
- */
- getClearColor( target ) {
- return target.copy( this._clearColor );
- }
- /**
- * Defines the clear color and optionally the clear alpha.
- *
- * @param {Color} color - The clear color.
- * @param {number} [alpha=1] - The clear alpha.
- */
- setClearColor( color, alpha = 1 ) {
- this._clearColor.set( color );
- this._clearColor.a = alpha;
- }
- /**
- * Returns the clear alpha.
- *
- * @return {number} The clear alpha.
- */
- getClearAlpha() {
- return this._clearColor.a;
- }
- /**
- * Defines the clear alpha.
- *
- * @param {number} alpha - The clear alpha.
- */
- setClearAlpha( alpha ) {
- this._clearColor.a = alpha;
- }
- /**
- * Returns the clear depth.
- *
- * @return {number} The clear depth.
- */
- getClearDepth() {
- return this._clearDepth;
- }
- /**
- * Defines the clear depth.
- *
- * @param {number} depth - The clear depth.
- */
- setClearDepth( depth ) {
- this._clearDepth = depth;
- }
- /**
- * Returns the clear stencil.
- *
- * @return {number} The clear stencil.
- */
- getClearStencil() {
- return this._clearStencil;
- }
- /**
- * Defines the clear stencil.
- *
- * @param {number} stencil - The clear stencil.
- */
- setClearStencil( stencil ) {
- this._clearStencil = stencil;
- }
- /**
- * This method performs an occlusion query for the given 3D object.
- * It returns `true` if the given 3D object is fully occluded by other
- * 3D objects in the scene.
- *
- * @param {Object3D} object - The 3D object to test.
- * @return {boolean} Whether the 3D object is fully occluded or not.
- */
- isOccluded( object ) {
- const renderContext = this._currentRenderContext;
- return renderContext && this.backend.isOccluded( renderContext, object );
- }
- /**
- * Performs a manual clear operation. This method ignores `autoClear` properties.
- *
- * @param {boolean} [color=true] - Whether the color buffer should be cleared or not.
- * @param {boolean} [depth=true] - Whether the depth buffer should be cleared or not.
- * @param {boolean} [stencil=true] - Whether the stencil buffer should be cleared or not.
- * @return {Promise} A Promise that resolves when the clear operation has been executed.
- * Only returned when the renderer has not been initialized.
- */
- clear( color = true, depth = true, stencil = true ) {
- if ( this._initialized === false ) {
- console.warn( 'THREE.Renderer: .clear() called before the backend is initialized. Try using .clearAsync() instead.' );
- return this.clearAsync( color, depth, stencil );
- }
- const renderTarget = this._renderTarget || this._getFrameBufferTarget();
- let renderContext = null;
- if ( renderTarget !== null ) {
- this._textures.updateRenderTarget( renderTarget );
- const renderTargetData = this._textures.get( renderTarget );
- renderContext = this._renderContexts.getForClear( renderTarget );
- renderContext.textures = renderTargetData.textures;
- renderContext.depthTexture = renderTargetData.depthTexture;
- renderContext.width = renderTargetData.width;
- renderContext.height = renderTargetData.height;
- renderContext.renderTarget = renderTarget;
- renderContext.depth = renderTarget.depthBuffer;
- renderContext.stencil = renderTarget.stencilBuffer;
- // #30329
- renderContext.clearColorValue = this.backend.getClearColor();
- }
- this.backend.clear( color, depth, stencil, renderContext );
- if ( renderTarget !== null && this._renderTarget === null ) {
- this._renderOutput( renderTarget );
- }
- }
- /**
- * Performs a manual clear operation of the color buffer. This method ignores `autoClear` properties.
- *
- * @return {Promise} A Promise that resolves when the clear operation has been executed.
- * Only returned when the renderer has not been initialized.
- */
- clearColor() {
- return this.clear( true, false, false );
- }
- /**
- * Performs a manual clear operation of the depth buffer. This method ignores `autoClear` properties.
- *
- * @return {Promise} A Promise that resolves when the clear operation has been executed.
- * Only returned when the renderer has not been initialized.
- */
- clearDepth() {
- return this.clear( false, true, false );
- }
- /**
- * Performs a manual clear operation of the stencil buffer. This method ignores `autoClear` properties.
- *
- * @return {Promise} A Promise that resolves when the clear operation has been executed.
- * Only returned when the renderer has not been initialized.
- */
- clearStencil() {
- return this.clear( false, false, true );
- }
- /**
- * Async version of {@link Renderer#clear}.
- *
- * @async
- * @param {boolean} [color=true] - Whether the color buffer should be cleared or not.
- * @param {boolean} [depth=true] - Whether the depth buffer should be cleared or not.
- * @param {boolean} [stencil=true] - Whether the stencil buffer should be cleared or not.
- * @return {Promise} A Promise that resolves when the clear operation has been executed.
- */
- async clearAsync( color = true, depth = true, stencil = true ) {
- if ( this._initialized === false ) await this.init();
- this.clear( color, depth, stencil );
- }
- /**
- * Async version of {@link Renderer#clearColor}.
- *
- * @async
- * @return {Promise} A Promise that resolves when the clear operation has been executed.
- */
- async clearColorAsync() {
- this.clearAsync( true, false, false );
- }
- /**
- * Async version of {@link Renderer#clearDepth}.
- *
- * @async
- * @return {Promise} A Promise that resolves when the clear operation has been executed.
- */
- async clearDepthAsync() {
- this.clearAsync( false, true, false );
- }
- /**
- * Async version of {@link Renderer#clearStencil}.
- *
- * @async
- * @return {Promise} A Promise that resolves when the clear operation has been executed.
- */
- async clearStencilAsync() {
- this.clearAsync( false, false, true );
- }
- /**
- * The current output tone mapping of the renderer. When a render target is set,
- * the output tone mapping is always `NoToneMapping`.
- *
- * @type {number}
- */
- get currentToneMapping() {
- return this.isOutputTarget ? this.toneMapping : NoToneMapping;
- }
- /**
- * The current output color space of the renderer. When a render target is set,
- * the output color space is always `LinearSRGBColorSpace`.
- *
- * @type {string}
- */
- get currentColorSpace() {
- return this.isOutputTarget ? this.outputColorSpace : LinearSRGBColorSpace;
- }
- /**
- * Returns `true` if the rendering settings are set to screen output.
- *
- * @returns {boolean} True if the current render target is the same of output render target or `null`, otherwise false.
- */
- get isOutputTarget() {
- return this._renderTarget === this._outputRenderTarget || this._renderTarget === null;
- }
- /**
- * Frees all internal resources of the renderer. Call this method if the renderer
- * is no longer in use by your app.
- */
- dispose() {
- this.info.dispose();
- this.backend.dispose();
- this._animation.dispose();
- this._objects.dispose();
- this._pipelines.dispose();
- this._nodes.dispose();
- this._bindings.dispose();
- this._renderLists.dispose();
- this._renderContexts.dispose();
- this._textures.dispose();
- if ( this._frameBufferTarget !== null ) this._frameBufferTarget.dispose();
- Object.values( this.backend.timestampQueryPool ).forEach( queryPool => {
- if ( queryPool !== null ) queryPool.dispose();
- } );
- this.setRenderTarget( null );
- this.setAnimationLoop( null );
- }
- /**
- * Sets the given render target. Calling this method means the renderer does not
- * target the default framebuffer (meaning the canvas) anymore but a custom framebuffer.
- * Use `null` as the first argument to reset the state.
- *
- * @param {?RenderTarget} renderTarget - The render target to set.
- * @param {number} [activeCubeFace=0] - The active cube face.
- * @param {number} [activeMipmapLevel=0] - The active mipmap level.
- */
- setRenderTarget( renderTarget, activeCubeFace = 0, activeMipmapLevel = 0 ) {
- this._renderTarget = renderTarget;
- this._activeCubeFace = activeCubeFace;
- this._activeMipmapLevel = activeMipmapLevel;
- }
- /**
- * Returns the current render target.
- *
- * @return {?RenderTarget} The render target. Returns `null` if no render target is set.
- */
- getRenderTarget() {
- return this._renderTarget;
- }
- /**
- * Sets the output render target for the renderer.
- *
- * @param {Object} renderTarget - The render target to set as the output target.
- */
- setOutputRenderTarget( renderTarget ) {
- this._outputRenderTarget = renderTarget;
- }
- /**
- * Returns the current output target.
- *
- * @return {?RenderTarget} The current output render target. Returns `null` if no output target is set.
- */
- getOutputRenderTarget() {
- return this._outputRenderTarget;
- }
- /**
- * Callback for {@link Renderer#setRenderObjectFunction}.
- *
- * @callback renderObjectFunction
- * @param {Object3D} object - The 3D object.
- * @param {Scene} scene - The scene the 3D object belongs to.
- * @param {Camera} camera - The camera the object should be rendered with.
- * @param {BufferGeometry} geometry - The object's geometry.
- * @param {Material} material - The object's material.
- * @param {?Object} group - Only relevant for objects using multiple materials. This represents a group entry from the respective `BufferGeometry`.
- * @param {LightsNode} lightsNode - The current lights node.
- * @param {ClippingContext} clippingContext - The clipping context.
- * @param {?string} [passId=null] - An optional ID for identifying the pass.
- */
- /**
- * Sets the given render object function. Calling this method overwrites the default implementation
- * which is {@link Renderer#renderObject}. Defining a custom function can be useful
- * if you want to modify the way objects are rendered. For example you can define things like "every
- * object that has material of a certain type should perform a pre-pass with a special overwrite material".
- * The custom function must always call `renderObject()` in its implementation.
- *
- * Use `null` as the first argument to reset the state.
- *
- * @param {?renderObjectFunction} renderObjectFunction - The render object function.
- */
- setRenderObjectFunction( renderObjectFunction ) {
- this._renderObjectFunction = renderObjectFunction;
- }
- /**
- * Returns the current render object function.
- *
- * @return {?Function} The current render object function. Returns `null` if no function is set.
- */
- getRenderObjectFunction() {
- return this._renderObjectFunction;
- }
- /**
- * Execute a single or an array of compute nodes. This method can only be called
- * if the renderer has been initialized.
- *
- * @param {Node|Array<Node>} computeNodes - The compute node(s).
- * @return {?Promise} A Promise that resolve when the compute has finished. Only returned when the renderer has not been initialized.
- */
- compute( computeNodes ) {
- if ( this._isDeviceLost === true ) return;
- if ( this._initialized === false ) {
- console.warn( 'THREE.Renderer: .compute() called before the backend is initialized. Try using .computeAsync() instead.' );
- return this.computeAsync( computeNodes );
- }
- //
- const nodeFrame = this._nodes.nodeFrame;
- const previousRenderId = nodeFrame.renderId;
- //
- this.info.calls ++;
- this.info.compute.calls ++;
- this.info.compute.frameCalls ++;
- nodeFrame.renderId = this.info.calls;
- //
- const backend = this.backend;
- const pipelines = this._pipelines;
- const bindings = this._bindings;
- const nodes = this._nodes;
- const computeList = Array.isArray( computeNodes ) ? computeNodes : [ computeNodes ];
- if ( computeList[ 0 ] === undefined || computeList[ 0 ].isComputeNode !== true ) {
- throw new Error( 'THREE.Renderer: .compute() expects a ComputeNode.' );
- }
- backend.beginCompute( computeNodes );
- for ( const computeNode of computeList ) {
- // onInit
- if ( pipelines.has( computeNode ) === false ) {
- const dispose = () => {
- computeNode.removeEventListener( 'dispose', dispose );
- pipelines.delete( computeNode );
- bindings.delete( computeNode );
- nodes.delete( computeNode );
- };
- computeNode.addEventListener( 'dispose', dispose );
- //
- const onInitFn = computeNode.onInitFunction;
- if ( onInitFn !== null ) {
- onInitFn.call( computeNode, { renderer: this } );
- }
- }
- nodes.updateForCompute( computeNode );
- bindings.updateForCompute( computeNode );
- const computeBindings = bindings.getForCompute( computeNode );
- const computePipeline = pipelines.getForCompute( computeNode, computeBindings );
- backend.compute( computeNodes, computeNode, computeBindings, computePipeline );
- }
- backend.finishCompute( computeNodes );
- //
- nodeFrame.renderId = previousRenderId;
- }
- /**
- * Execute a single or an array of compute nodes.
- *
- * @async
- * @param {Node|Array<Node>} computeNodes - The compute node(s).
- * @return {Promise} A Promise that resolve when the compute has finished.
- */
- async computeAsync( computeNodes ) {
- if ( this._initialized === false ) await this.init();
- this.compute( computeNodes );
- }
- /**
- * Checks if the given feature is supported by the selected backend.
- *
- * @async
- * @param {string} name - The feature's name.
- * @return {Promise<boolean>} A Promise that resolves with a bool that indicates whether the feature is supported or not.
- */
- async hasFeatureAsync( name ) {
- if ( this._initialized === false ) await this.init();
- return this.backend.hasFeature( name );
- }
- async resolveTimestampsAsync( type = 'render' ) {
- if ( this._initialized === false ) await this.init();
- return this.backend.resolveTimestampsAsync( type );
- }
- /**
- * Checks if the given feature is supported by the selected backend. If the
- * renderer has not been initialized, this method always returns `false`.
- *
- * @param {string} name - The feature's name.
- * @return {boolean} Whether the feature is supported or not.
- */
- hasFeature( name ) {
- if ( this._initialized === false ) {
- console.warn( 'THREE.Renderer: .hasFeature() called before the backend is initialized. Try using .hasFeatureAsync() instead.' );
- return false;
- }
- return this.backend.hasFeature( name );
- }
- /**
- * Returns `true` when the renderer has been initialized.
- *
- * @return {boolean} Whether the renderer has been initialized or not.
- */
- hasInitialized() {
- return this._initialized;
- }
- /**
- * Initializes the given textures. Useful for preloading a texture rather than waiting until first render
- * (which can cause noticeable lags due to decode and GPU upload overhead).
- *
- * @async
- * @param {Texture} texture - The texture.
- * @return {Promise} A Promise that resolves when the texture has been initialized.
- */
- async initTextureAsync( texture ) {
- if ( this._initialized === false ) await this.init();
- this._textures.updateTexture( texture );
- }
- /**
- * Initializes the given textures. Useful for preloading a texture rather than waiting until first render
- * (which can cause noticeable lags due to decode and GPU upload overhead).
- *
- * This method can only be used if the renderer has been initialized.
- *
- * @param {Texture} texture - The texture.
- */
- initTexture( texture ) {
- if ( this._initialized === false ) {
- console.warn( 'THREE.Renderer: .initTexture() called before the backend is initialized. Try using .initTextureAsync() instead.' );
- }
- this._textures.updateTexture( texture );
- }
- /**
- * Copies the current bound framebuffer into the given texture.
- *
- * @param {FramebufferTexture} framebufferTexture - The texture.
- * @param {Vector2|Vector4} rectangle - A two or four dimensional vector that defines the rectangular portion of the framebuffer that should be copied.
- */
- copyFramebufferToTexture( framebufferTexture, rectangle = null ) {
- if ( rectangle !== null ) {
- if ( rectangle.isVector2 ) {
- rectangle = _vector4.set( rectangle.x, rectangle.y, framebufferTexture.image.width, framebufferTexture.image.height ).floor();
- } else if ( rectangle.isVector4 ) {
- rectangle = _vector4.copy( rectangle ).floor();
- } else {
- console.error( 'THREE.Renderer.copyFramebufferToTexture: Invalid rectangle.' );
- return;
- }
- } else {
- rectangle = _vector4.set( 0, 0, framebufferTexture.image.width, framebufferTexture.image.height );
- }
- //
- let renderContext = this._currentRenderContext;
- let renderTarget;
- if ( renderContext !== null ) {
- renderTarget = renderContext.renderTarget;
- } else {
- renderTarget = this._renderTarget || this._getFrameBufferTarget();
- if ( renderTarget !== null ) {
- this._textures.updateRenderTarget( renderTarget );
- renderContext = this._textures.get( renderTarget );
- }
- }
- //
- this._textures.updateTexture( framebufferTexture, { renderTarget } );
- this.backend.copyFramebufferToTexture( framebufferTexture, renderContext, rectangle );
- }
- /**
- * Copies data of source texture into a destination texture.
- *
- * @param {Texture} srcTexture - The source texture.
- * @param {Texture} dstTexture - The destination texture.
- * @param {Box2|Box3} [srcRegion=null] - A bounding box which describes the source region. Can be two or three-dimensional.
- * @param {Vector2|Vector3} [dstPosition=null] - A vector that represents the origin of the destination region. Can be two or three-dimensional.
- * @param {number} level - The mipmap level to copy.
- */
- copyTextureToTexture( srcTexture, dstTexture, srcRegion = null, dstPosition = null, level = 0 ) {
- this._textures.updateTexture( srcTexture );
- this._textures.updateTexture( dstTexture );
- this.backend.copyTextureToTexture( srcTexture, dstTexture, srcRegion, dstPosition, level );
- }
- /**
- * Reads pixel data from the given render target.
- *
- * @async
- * @param {RenderTarget} renderTarget - The render target to read from.
- * @param {number} x - The `x` coordinate of the copy region's origin.
- * @param {number} y - The `y` coordinate of the copy region's origin.
- * @param {number} width - The width of the copy region.
- * @param {number} height - The height of the copy region.
- * @param {number} [textureIndex=0] - The texture index of a MRT render target.
- * @param {number} [faceIndex=0] - The active cube face index.
- * @return {Promise<TypedArray>} A Promise that resolves when the read has been finished. The resolve provides the read data as a typed array.
- */
- async readRenderTargetPixelsAsync( renderTarget, x, y, width, height, textureIndex = 0, faceIndex = 0 ) {
- return this.backend.copyTextureToBuffer( renderTarget.textures[ textureIndex ], x, y, width, height, faceIndex );
- }
- /**
- * Analyzes the given 3D object's hierarchy and builds render lists from the
- * processed hierarchy.
- *
- * @param {Object3D} object - The 3D object to process (usually a scene).
- * @param {Camera} camera - The camera the object is rendered with.
- * @param {number} groupOrder - The group order is derived from the `renderOrder` of groups and is used to group 3D objects within groups.
- * @param {RenderList} renderList - The current render list.
- * @param {ClippingContext} clippingContext - The current clipping context.
- */
- _projectObject( object, camera, groupOrder, renderList, clippingContext ) {
- if ( object.visible === false ) return;
- const visible = object.layers.test( camera.layers );
- if ( visible ) {
- if ( object.isGroup ) {
- groupOrder = object.renderOrder;
- if ( object.isClippingGroup && object.enabled ) clippingContext = clippingContext.getGroupContext( object );
- } else if ( object.isLOD ) {
- if ( object.autoUpdate === true ) object.update( camera );
- } else if ( object.isLight ) {
- renderList.pushLight( object );
- } else if ( object.isSprite ) {
- if ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) {
- if ( this.sortObjects === true ) {
- _vector4.setFromMatrixPosition( object.matrixWorld ).applyMatrix4( _projScreenMatrix );
- }
- const { geometry, material } = object;
- if ( material.visible ) {
- renderList.push( object, geometry, material, groupOrder, _vector4.z, null, clippingContext );
- }
- }
- } else if ( object.isLineLoop ) {
- console.error( 'THREE.Renderer: Objects of type THREE.LineLoop are not supported. Please use THREE.Line or THREE.LineSegments.' );
- } else if ( object.isMesh || object.isLine || object.isPoints ) {
- if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) {
- const { geometry, material } = object;
- if ( this.sortObjects === true ) {
- if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
- _vector4
- .copy( geometry.boundingSphere.center )
- .applyMatrix4( object.matrixWorld )
- .applyMatrix4( _projScreenMatrix );
- }
- if ( Array.isArray( material ) ) {
- const groups = geometry.groups;
- for ( let i = 0, l = groups.length; i < l; i ++ ) {
- const group = groups[ i ];
- const groupMaterial = material[ group.materialIndex ];
- if ( groupMaterial && groupMaterial.visible ) {
- renderList.push( object, geometry, groupMaterial, groupOrder, _vector4.z, group, clippingContext );
- }
- }
- } else if ( material.visible ) {
- renderList.push( object, geometry, material, groupOrder, _vector4.z, null, clippingContext );
- }
- }
- }
- }
- if ( object.isBundleGroup === true && this.backend.beginBundle !== undefined ) {
- const baseRenderList = renderList;
- // replace render list
- renderList = this._renderLists.get( object, camera );
- renderList.begin();
- baseRenderList.pushBundle( {
- bundleGroup: object,
- camera,
- renderList,
- } );
- renderList.finish();
- }
- const children = object.children;
- for ( let i = 0, l = children.length; i < l; i ++ ) {
- this._projectObject( children[ i ], camera, groupOrder, renderList, clippingContext );
- }
- }
- /**
- * Renders the given render bundles.
- *
- * @private
- * @param {Array<Object>} bundles - Array with render bundle data.
- * @param {Scene} sceneRef - The scene the render bundles belong to.
- * @param {LightsNode} lightsNode - The current lights node.
- */
- _renderBundles( bundles, sceneRef, lightsNode ) {
- for ( const bundle of bundles ) {
- this._renderBundle( bundle, sceneRef, lightsNode );
- }
- }
- /**
- * Renders the transparent objects from the given render lists.
- *
- * @private
- * @param {Array<Object>} renderList - The transparent render list.
- * @param {Array<Object>} doublePassList - The list of transparent objects which require a double pass (e.g. because of transmission).
- * @param {Camera} camera - The camera the render list should be rendered with.
- * @param {Scene} scene - The scene the render list belongs to.
- * @param {LightsNode} lightsNode - The current lights node.
- */
- _renderTransparents( renderList, doublePassList, camera, scene, lightsNode ) {
- if ( doublePassList.length > 0 ) {
- // render back side
- for ( const { material } of doublePassList ) {
- material.side = BackSide;
- }
- this._renderObjects( doublePassList, camera, scene, lightsNode, 'backSide' );
- // render front side
- for ( const { material } of doublePassList ) {
- material.side = FrontSide;
- }
- this._renderObjects( renderList, camera, scene, lightsNode );
- // restore
- for ( const { material } of doublePassList ) {
- material.side = DoubleSide;
- }
- } else {
- this._renderObjects( renderList, camera, scene, lightsNode );
- }
- }
- /**
- * Renders the objects from the given render list.
- *
- * @private
- * @param {Array<Object>} renderList - The render list.
- * @param {Camera} camera - The camera the render list should be rendered with.
- * @param {Scene} scene - The scene the render list belongs to.
- * @param {LightsNode} lightsNode - The current lights node.
- * @param {?string} [passId=null] - An optional ID for identifying the pass.
- */
- _renderObjects( renderList, camera, scene, lightsNode, passId = null ) {
- for ( let i = 0, il = renderList.length; i < il; i ++ ) {
- const { object, geometry, material, group, clippingContext } = renderList[ i ];
- this._currentRenderObjectFunction( object, scene, camera, geometry, material, group, lightsNode, clippingContext, passId );
- }
- }
- /**
- * This method represents the default render object function that manages the render lifecycle
- * of the object.
- *
- * @param {Object3D} object - The 3D object.
- * @param {Scene} scene - The scene the 3D object belongs to.
- * @param {Camera} camera - The camera the object should be rendered with.
- * @param {BufferGeometry} geometry - The object's geometry.
- * @param {Material} material - The object's material.
- * @param {?Object} group - Only relevant for objects using multiple materials. This represents a group entry from the respective `BufferGeometry`.
- * @param {LightsNode} lightsNode - The current lights node.
- * @param {ClippingContext} clippingContext - The clipping context.
- * @param {?string} [passId=null] - An optional ID for identifying the pass.
- */
- renderObject( object, scene, camera, geometry, material, group, lightsNode, clippingContext = null, passId = null ) {
- let overridePositionNode;
- let overrideColorNode;
- let overrideDepthNode;
- //
- object.onBeforeRender( this, scene, camera, geometry, material, group );
- //
- if ( scene.overrideMaterial !== null ) {
- const overrideMaterial = scene.overrideMaterial;
- if ( material.positionNode && material.positionNode.isNode ) {
- overridePositionNode = overrideMaterial.positionNode;
- overrideMaterial.positionNode = material.positionNode;
- }
- overrideMaterial.alphaTest = material.alphaTest;
- overrideMaterial.alphaMap = material.alphaMap;
- overrideMaterial.transparent = material.transparent || material.transmission > 0;
- if ( overrideMaterial.isShadowPassMaterial ) {
- overrideMaterial.side = material.shadowSide === null ? material.side : material.shadowSide;
- if ( material.depthNode && material.depthNode.isNode ) {
- overrideDepthNode = overrideMaterial.depthNode;
- overrideMaterial.depthNode = material.depthNode;
- }
- if ( material.castShadowNode && material.castShadowNode.isNode ) {
- overrideColorNode = overrideMaterial.colorNode;
- overrideMaterial.colorNode = material.castShadowNode;
- }
- }
- material = overrideMaterial;
- }
- //
- if ( material.transparent === true && material.side === DoubleSide && material.forceSinglePass === false ) {
- material.side = BackSide;
- this._handleObjectFunction( object, material, scene, camera, lightsNode, group, clippingContext, 'backSide' ); // create backSide pass id
- material.side = FrontSide;
- this._handleObjectFunction( object, material, scene, camera, lightsNode, group, clippingContext, passId ); // use default pass id
- material.side = DoubleSide;
- } else {
- this._handleObjectFunction( object, material, scene, camera, lightsNode, group, clippingContext, passId );
- }
- //
- if ( overridePositionNode !== undefined ) {
- scene.overrideMaterial.positionNode = overridePositionNode;
- }
- if ( overrideDepthNode !== undefined ) {
- scene.overrideMaterial.depthNode = overrideDepthNode;
- }
- if ( overrideColorNode !== undefined ) {
- scene.overrideMaterial.colorNode = overrideColorNode;
- }
- //
- object.onAfterRender( this, scene, camera, geometry, material, group );
- }
- /**
- * This method represents the default `_handleObjectFunction` implementation which creates
- * a render object from the given data and performs the draw command with the selected backend.
- *
- * @private
- * @param {Object3D} object - The 3D object.
- * @param {Material} material - The object's material.
- * @param {Scene} scene - The scene the 3D object belongs to.
- * @param {Camera} camera - The camera the object should be rendered with.
- * @param {LightsNode} lightsNode - The current lights node.
- * @param {?{start: number, count: number}} group - Only relevant for objects using multiple materials. This represents a group entry from the respective `BufferGeometry`.
- * @param {ClippingContext} clippingContext - The clipping context.
- * @param {?string} [passId=null] - An optional ID for identifying the pass.
- */
- _renderObjectDirect( object, material, scene, camera, lightsNode, group, clippingContext, passId ) {
- const renderObject = this._objects.get( object, material, scene, camera, lightsNode, this._currentRenderContext, clippingContext, passId );
- renderObject.drawRange = object.geometry.drawRange;
- renderObject.group = group;
- //
- const needsRefresh = this._nodes.needsRefresh( renderObject );
- if ( needsRefresh ) {
- this._nodes.updateBefore( renderObject );
- this._geometries.updateForRender( renderObject );
- this._nodes.updateForRender( renderObject );
- this._bindings.updateForRender( renderObject );
- }
- this._pipelines.updateForRender( renderObject );
- //
- if ( this._currentRenderBundle !== null ) {
- const renderBundleData = this.backend.get( this._currentRenderBundle );
- renderBundleData.renderObjects.push( renderObject );
- renderObject.bundle = this._currentRenderBundle.bundleGroup;
- }
- this.backend.draw( renderObject, this.info );
- if ( needsRefresh ) this._nodes.updateAfter( renderObject );
- }
- /**
- * A different implementation for `_handleObjectFunction` which only makes sure the object is ready for rendering.
- * Used in `compileAsync()`.
- *
- * @private
- * @param {Object3D} object - The 3D object.
- * @param {Material} material - The object's material.
- * @param {Scene} scene - The scene the 3D object belongs to.
- * @param {Camera} camera - The camera the object should be rendered with.
- * @param {LightsNode} lightsNode - The current lights node.
- * @param {?{start: number, count: number}} group - Only relevant for objects using multiple materials. This represents a group entry from the respective `BufferGeometry`.
- * @param {ClippingContext} clippingContext - The clipping context.
- * @param {?string} [passId=null] - An optional ID for identifying the pass.
- */
- _createObjectPipeline( object, material, scene, camera, lightsNode, group, clippingContext, passId ) {
- const renderObject = this._objects.get( object, material, scene, camera, lightsNode, this._currentRenderContext, clippingContext, passId );
- renderObject.drawRange = object.geometry.drawRange;
- renderObject.group = group;
- //
- this._nodes.updateBefore( renderObject );
- this._geometries.updateForRender( renderObject );
- this._nodes.updateForRender( renderObject );
- this._bindings.updateForRender( renderObject );
- this._pipelines.getForRender( renderObject, this._compilationPromises );
- this._nodes.updateAfter( renderObject );
- }
- /**
- * Alias for `compileAsync()`.
- *
- * @method
- * @param {Object3D} scene - The scene or 3D object to precompile.
- * @param {Camera} camera - The camera that is used to render the scene.
- * @param {Scene} targetScene - If the first argument is a 3D object, this parameter must represent the scene the 3D object is going to be added.
- * @return {Promise} A Promise that resolves when the compile has been finished.
- */
- get compile() {
- return this.compileAsync;
- }
- }
- export default Renderer;
|