123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227 |
- import { Matrix } from "../Maths/math.vector.js";
- import { ShaderMaterial } from "../Materials/shaderMaterial.js";
- import { RenderTargetTexture } from "../Materials/Textures/renderTargetTexture.js";
- import { Color4 } from "../Maths/math.color.js";
- import { PostProcess } from "../PostProcesses/postProcess.js";
- import "../Shaders/meshUVSpaceRenderer.vertex.js";
- import "../Shaders/meshUVSpaceRenderer.fragment.js";
- import "../Shaders/meshUVSpaceRendererMasker.vertex.js";
- import "../Shaders/meshUVSpaceRendererMasker.fragment.js";
- import "../Shaders/meshUVSpaceRendererFinaliser.fragment.js";
- import "../Shaders/meshUVSpaceRendererFinaliser.vertex.js";
- /**
- * Class used to render in the mesh UV space
- * @since 5.49.1
- */
- export class MeshUVSpaceRenderer {
- static _GetShader(scene) {
- if (!scene._meshUVSpaceRendererShader) {
- const shader = new ShaderMaterial("meshUVSpaceRendererShader", scene, {
- vertex: "meshUVSpaceRenderer",
- fragment: "meshUVSpaceRenderer",
- }, {
- attributes: ["position", "normal", "uv"],
- uniforms: ["world", "projMatrix"],
- samplers: ["textureSampler"],
- needAlphaBlending: true,
- });
- shader.backFaceCulling = false;
- shader.alphaMode = 2;
- scene.onDisposeObservable.add(() => {
- scene._meshUVSpaceRendererShader?.dispose();
- scene._meshUVSpaceRendererShader = null;
- });
- scene._meshUVSpaceRendererShader = shader;
- }
- return scene._meshUVSpaceRendererShader;
- }
- static _GetMaskShader(scene) {
- if (!scene._meshUVSpaceRendererMaskShader) {
- const shader = new ShaderMaterial("meshUVSpaceRendererMaskShader", scene, {
- vertex: "meshUVSpaceRendererMasker",
- fragment: "meshUVSpaceRendererMasker",
- }, {
- attributes: ["position", "uv"],
- uniforms: ["worldViewProjection"],
- });
- shader.backFaceCulling = false;
- shader.alphaMode = 2;
- scene.onDisposeObservable.add(() => {
- scene._meshUVSpaceRendererMaskShader?.dispose();
- scene._meshUVSpaceRendererMaskShader = null;
- });
- scene._meshUVSpaceRendererMaskShader = shader;
- }
- return scene._meshUVSpaceRendererMaskShader;
- }
- static _IsRenderTargetTexture(texture) {
- return texture.renderList !== undefined;
- }
- /**
- * Creates a new MeshUVSpaceRenderer
- * @param mesh The mesh used for the source UV space
- * @param scene The scene the mesh belongs to
- * @param options The options to use when creating the texture
- */
- constructor(mesh, scene, options) {
- this._textureCreatedInternally = false;
- this._configureUserCreatedTexture = true;
- this._maskTexture = null;
- this._finalPostProcess = null;
- /**
- * Clear color of the texture
- */
- this.clearColor = new Color4(0, 0, 0, 0);
- this._mesh = mesh;
- this._scene = scene;
- this._options = {
- width: 1024,
- height: 1024,
- textureType: 0,
- generateMipMaps: true,
- optimizeUVAllocation: true,
- uvEdgeBlending: false,
- ...options,
- };
- }
- /**
- * Checks if the texture is ready to be used
- * @returns true if the texture is ready to be used
- */
- isReady() {
- if (!this.texture) {
- this._createDiffuseRTT();
- }
- const textureIsReady = MeshUVSpaceRenderer._IsRenderTargetTexture(this.texture) ? this.texture.isReadyForRendering() : this.texture.isReady();
- const maskIsReady = this._maskTexture?.isReadyForRendering() ?? true;
- const postProcessIsReady = this._finalPostProcess?.isReady() ?? true;
- return textureIsReady && maskIsReady && postProcessIsReady;
- }
- /**
- * Projects and renders a texture in the mesh UV space
- * @param texture The texture
- * @param position The position of the center of projection (world space coordinates)
- * @param normal The direction of the projection (world space coordinates)
- * @param size The size of the projection
- * @param angle The rotation angle around the direction of the projection
- */
- renderTexture(texture, position, normal, size, angle = 0) {
- if (!this.texture) {
- this._createDiffuseRTT();
- }
- else if (this._configureUserCreatedTexture) {
- this._configureUserCreatedRTT();
- }
- if (MeshUVSpaceRenderer._IsRenderTargetTexture(this.texture)) {
- const matrix = this._createProjectionMatrix(position, normal, size, angle);
- const shader = MeshUVSpaceRenderer._GetShader(this._scene);
- shader.setTexture("textureSampler", texture);
- shader.setMatrix("projMatrix", matrix);
- this.texture.render();
- }
- }
- /**
- * Clears the texture map
- */
- clear() {
- if (MeshUVSpaceRenderer._IsRenderTargetTexture(this.texture) && this.texture.renderTarget) {
- const engine = this._scene.getEngine();
- engine.bindFramebuffer(this.texture.renderTarget);
- engine.clear(this.clearColor, true, true, true);
- engine.unBindFramebuffer(this.texture.renderTarget);
- }
- if (this._finalPostProcess?.inputTexture) {
- const engine = this._scene.getEngine();
- engine.bindFramebuffer(this._finalPostProcess?.inputTexture);
- engine.clear(this.clearColor, true, true, true);
- engine.unBindFramebuffer(this._finalPostProcess?.inputTexture);
- }
- }
- /**
- * Disposes of the resources
- */
- dispose() {
- if (this._textureCreatedInternally) {
- this.texture.dispose();
- this._textureCreatedInternally = false;
- }
- this._configureUserCreatedTexture = true;
- this._maskTexture?.dispose();
- this._maskTexture = null;
- this._finalPostProcess?.dispose();
- this._finalPostProcess = null;
- }
- _configureUserCreatedRTT() {
- this._configureUserCreatedTexture = false;
- if (MeshUVSpaceRenderer._IsRenderTargetTexture(this.texture)) {
- this.texture.setMaterialForRendering(this._mesh, MeshUVSpaceRenderer._GetShader(this._scene));
- this.texture.onClearObservable.add(() => { });
- this.texture.renderList = [this._mesh];
- if (this._options.uvEdgeBlending) {
- this._createMaskTexture();
- this._createPostProcess();
- this.texture.addPostProcess(this._finalPostProcess);
- }
- }
- }
- _createDiffuseRTT() {
- this._textureCreatedInternally = true;
- const texture = this._createRenderTargetTexture(this._options.width, this._options.height);
- texture.setMaterialForRendering(this._mesh, MeshUVSpaceRenderer._GetShader(this._scene));
- this.texture = texture;
- this._configureUserCreatedTexture = false;
- if (this._options.uvEdgeBlending) {
- this._createMaskTexture();
- this._createPostProcess();
- texture.addPostProcess(this._finalPostProcess);
- }
- }
- _createMaskTexture() {
- if (this._maskTexture) {
- return;
- }
- this._maskTexture = new RenderTargetTexture(this._mesh.name + "_maskTexture", { width: this._options.width, height: this._options.height }, this._scene, false, // No mipmaps for the mask texture
- true, 0, false, 2, undefined, undefined, undefined, 6);
- this._maskTexture.clearColor = new Color4(0, 0, 0, 0);
- // Render the mesh with the mask material to the mask texture
- this._maskTexture.renderList.push(this._mesh);
- this._maskTexture.setMaterialForRendering(this._mesh, MeshUVSpaceRenderer._GetMaskShader(this._scene));
- // Ensure the mask texture is updated
- this._maskTexture.refreshRate = RenderTargetTexture.REFRESHRATE_RENDER_ONCE;
- this._scene.customRenderTargets.push(this._maskTexture);
- }
- _createPostProcess() {
- if (this._finalPostProcess) {
- return;
- }
- this._finalPostProcess = new PostProcess(this._mesh.name + "_fixSeamsPostProcess", "meshUVSpaceRendererFinaliser", ["textureSize"], ["textureSampler", "maskTextureSampler"], 1.0, null, 1, this._scene.getEngine(), false, null, this._options.textureType);
- this._finalPostProcess.onApplyObservable.add((effect) => {
- effect.setTexture("maskTextureSampler", this._maskTexture);
- effect.setFloat2("textureSize", this._options.width, this._options.height);
- });
- }
- _createRenderTargetTexture(width, height) {
- const rtt = new RenderTargetTexture(this._mesh.name + "_uvspaceTexture", { width, height }, this._scene, this._options.generateMipMaps, true, this._options.textureType, false, this._options.generateMipMaps ? 3 : 2, false, false, false, 5);
- rtt.renderParticles = false;
- rtt.optimizeUVAllocation = !!this._options.optimizeUVAllocation;
- rtt.onClearObservable.addOnce(() => {
- this._scene.getEngine().clear(this.clearColor, true, true, true);
- rtt.onClearObservable.add(() => { }); // this disables clearing the texture for the next frames
- });
- rtt.renderList = [this._mesh];
- return rtt;
- }
- _createProjectionMatrix(position, normal, size, angle = 0) {
- const yaw = -Math.atan2(normal.z, normal.x) - Math.PI / 2;
- const len = Math.sqrt(normal.x * normal.x + normal.z * normal.z);
- const pitch = Math.atan2(normal.y, len);
- const p = position.add(normal.scale(size.z * 0.5));
- const projWorldMatrix = Matrix.RotationYawPitchRoll(yaw, pitch, angle).multiply(Matrix.Translation(p.x, p.y, p.z));
- const inverseProjWorldMatrix = Matrix.Invert(projWorldMatrix);
- const projMatrix = Matrix.FromArray([2 / size.x, 0, 0, 0, 0, 2 / size.y, 0, 0, 0, 0, 1 / size.z, 0, 0, 0, 0, 1]);
- const screenMatrix = Matrix.FromArray([0.5, 0, 0, 0, 0, 0.5, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.0, 1]);
- return inverseProjWorldMatrix.multiply(projMatrix).multiply(screenMatrix);
- }
- }
- //# sourceMappingURL=meshUVSpaceRenderer.js.map
|