UNPKG

@polygonjs/polygonjs

Version:

node-based WebGL 3D engine https://polygonjs.com

291 lines (290 loc) 11.3 kB
"use strict"; import { Vector2, Scene, BufferGeometry, BufferAttribute, Mesh, WebGLRenderTarget, ClampToEdgeWrapping, NearestFilter, RGBAFormat, HalfFloatType, Vector3, OrthographicCamera, Sphere } from "three"; import { adjacencyTexture, distancesTexture, positionTexture, viscositySpringTexture, createTexturesFromAllocation } from "./ClothAttributeToTexture"; export function clothMaterialCopyConfigRef(src, target) { target.tSize.value.copy(src.tSize.value); } function textureContainerToRef(src, ref) { if (src.texture) { ref.value = src.texture; } } export class ClothFBOController { constructor(mainController) { this.mainController = mainController; this.tSize = new Vector2(); this.fboScene = new Scene(); this.fboCamera = new OrthographicCamera(); this.RESOLUTION = new Vector2(); this.originalRT = { texture: null }; this.viscositySpringT = { texture: null }; this.previousRT = new Array(2); this.targetRT = new Array(2); this.positionRT = new Array(2); this.adjacentsRT = new Array(2); this.distancesRT = new Array(2); this._initialized = false; this.RESOLUTION.copy(this.mainController.geometryInit.resolution); this.tSize.set(this.RESOLUTION.x, this.RESOLUTION.y); const geometry = new BufferGeometry(); const positions = new Float32Array([-1, -1, 3, -1, -1, 3]); geometry.setAttribute("position", new BufferAttribute(positions, 2)); geometry.boundingSphere = new Sphere(new Vector3(0, 0, 0), 5); this.fboMesh = new Mesh(geometry, this.mainController.materials.copyShader); this.fboMesh.frustumCulled = false; this.fboScene.add(this.fboMesh); this.fboScene.updateMatrixWorld = function() { }; this.normalsRT = createRenderTarget(this.RESOLUTION); } init(renderer) { if (this._initialized) { return; } this._initialized = true; this.renderer = renderer; const originalRenderTarget = renderer.getRenderTarget(); this.createPositionTexture(); this.createViscositySpringTexture(); this.createTexturesFromAllocation(); for (let i = 0; i < 2; i++) { this.createAdjacentsTexture(i); this.createDistancesTexture(i); this.positionRT[i] = createRenderTarget(this.RESOLUTION); this.previousRT[i] = createRenderTarget(this.RESOLUTION); this.targetRT[i] = createRenderTarget(this.RESOLUTION); this.copyTexture(this.originalRT, this.positionRT[i], !i, renderer); this.copyTexture(this.originalRT, this.previousRT[i], !i, renderer); } renderer.setRenderTarget(originalRenderTarget); } copyTexture(input, output, order, renderer) { const copyShader = this.mainController.materials.copyShader; this.fboMesh.material = copyShader; copyShader.uniforms.order.value = order ? 1 : -1; copyShader.uniforms.tSize.value = this.tSize; copyShader.uniforms.texture.value = input.texture; renderer.setRenderTarget(output); renderer.render(this.fboScene, this.fboCamera); } // // // create textures // // createPositionTexture() { this.originalRT = { texture: positionTexture( this.mainController.geometryInit.geometry, // this.mainController.geometryInit.vertices, this.RESOLUTION ) }; } createViscositySpringTexture() { const texture = viscositySpringTexture(this.mainController.geometryInit.geometry, this.RESOLUTION); if (texture) { this.viscositySpringT = { texture }; } } createTexturesFromAllocation() { const allocation = this.mainController.textureAllocationsController(); if (!allocation) { return; } const texturesByName = createTexturesFromAllocation( this.mainController.geometryInit.geometry, this.RESOLUTION, allocation ); this.mainController.assignReadonlyTextures(this.mainController.materials.integrateShader, texturesByName); } createAdjacentsTexture(k) { this.adjacentsRT[k] = { texture: adjacencyTexture( this.mainController.geometryInit.geometry, this.RESOLUTION, this.mainController.geometryInit.adjacency, k ) }; } createDistancesTexture(k) { this.distancesRT[k] = { texture: distancesTexture( this.mainController.geometryInit.geometry, // this.mainController.geometryInit.vertices, this.RESOLUTION, this.mainController.geometryInit.adjacency, k ) }; } // // // update // // update(config) { const renderer = this.renderer; if (!(renderer && this._initialized)) { return; } const originalRenderTarget = renderer.getRenderTarget(); this.integrate(renderer); const selectedVertexIndex = this.mainController.selectedVertexIndex(); const steps = this.mainController.stepsCount; for (let i = 0; i < steps; i++) { if (selectedVertexIndex >= 0 && i < steps - 5) { this.mouseOffset(renderer); } this.solveConstraints(renderer, i == steps - 1 ? 1 : 0); } this.computeVertexNormals(renderer); renderer.setRenderTarget(originalRenderTarget); if (config) { this._updateTextureRefs(config); } } _updateTextureRefs(config) { config.tSize.value = this.mainController.fbo.tSize; config.tPosition0.value = this.positionRT[0].texture; config.tPosition1.value = this.positionRT[1].texture; config.tNormal.value = this.normalsRT.texture; textureContainerToRef(this.originalRT, config.tOriginalRT); textureContainerToRef(this.viscositySpringT, config.tViscositySpringT); config.tPreviousRT0.value = this.previousRT[0].texture; config.tPreviousRT1.value = this.previousRT[1].texture; config.tTargetRT0.value = this.targetRT[0].texture; config.tTargetRT1.value = this.targetRT[1].texture; config.tNormalsRT.value = this.normalsRT.texture; config.tPositionRT0.value = this.positionRT[0].texture; config.tPositionRT1.value = this.positionRT[1].texture; textureContainerToRef(this.adjacentsRT[0], config.tAdjacentsRT0); textureContainerToRef(this.adjacentsRT[1], config.tAdjacentsRT1); textureContainerToRef(this.distancesRT[0], config.tDistanceRT0); textureContainerToRef(this.distancesRT[1], config.tDistanceRT1); config.integrationMat.value = this.mainController.materials.integrateShader; } integrate(renderer) { const integrateShader = this.mainController.materials.integrateShader; this.fboMesh.material = integrateShader; integrateShader.uniforms.viscosity.value = this.mainController.viscosity; integrateShader.uniforms.spring.value = this.mainController.spring; integrateShader.uniforms.tSize.value.copy(this.tSize); integrateShader.uniforms.tOriginal.value = this.originalRT.texture; integrateShader.uniforms.tPrevious0.value = this.previousRT[0].texture; integrateShader.uniforms.tPrevious1.value = this.previousRT[1].texture; integrateShader.uniforms.tPosition0.value = this.positionRT[0].texture; integrateShader.uniforms.tPosition1.value = this.positionRT[1].texture; integrateShader.uniforms.tViscositySpring.value = this.viscositySpringT.texture; integrateShader.uniforms.order.value = 1; renderer.setRenderTarget(this.targetRT[0]); renderer.render(this.fboScene, this.fboCamera); integrateShader.uniforms.order.value = -1; renderer.setRenderTarget(this.targetRT[1]); renderer.render(this.fboScene, this.fboCamera); let tmp = this.previousRT[0]; this.previousRT[0] = this.positionRT[0]; this.positionRT[0] = this.targetRT[0]; this.targetRT[0] = tmp; tmp = this.previousRT[1]; this.previousRT[1] = this.positionRT[1]; this.positionRT[1] = this.targetRT[1]; this.targetRT[1] = tmp; } solveConstraints(renderer, secondaryMotionMult) { const constraintsShader = this.mainController.materials.constraintsShader; this.fboMesh.material = constraintsShader; constraintsShader.uniforms.constraintInfluence.value = this.mainController.constraintInfluence; constraintsShader.uniforms.tSize.value.copy(this.tSize); constraintsShader.uniforms.tPosition0.value = this.positionRT[0].texture; constraintsShader.uniforms.tPosition1.value = this.positionRT[1].texture; constraintsShader.uniforms.tAdjacentsA.value = this.adjacentsRT[0].texture; constraintsShader.uniforms.tAdjacentsB.value = this.adjacentsRT[1].texture; constraintsShader.uniforms.tDistancesA.value = this.distancesRT[0].texture; constraintsShader.uniforms.tDistancesB.value = this.distancesRT[1].texture; constraintsShader.uniforms.secondaryMotionMult.value = secondaryMotionMult; constraintsShader.uniforms.order.value = 1; renderer.setRenderTarget(this.targetRT[0]); renderer.render(this.fboScene, this.fboCamera); constraintsShader.uniforms.order.value = -1; renderer.setRenderTarget(this.targetRT[1]); renderer.render(this.fboScene, this.fboCamera); let tmp = this.positionRT[0]; this.positionRT[0] = this.targetRT[0]; this.targetRT[0] = tmp; tmp = this.positionRT[1]; this.positionRT[1] = this.targetRT[1]; this.targetRT[1] = tmp; } mouseOffset(renderer) { const mouseShader = this.mainController.materials.mouseShader; this.fboMesh.material = mouseShader; mouseShader.uniforms.tSize.value.copy(this.tSize); mouseShader.uniforms.vertex.value = this.mainController.selectedVertexIndex(); this.mainController.constraintPosition(mouseShader.uniforms.coordinates.value); mouseShader.uniforms.tOriginal.value = this.originalRT.texture; mouseShader.uniforms.tPosition0.value = this.positionRT[0].texture; mouseShader.uniforms.tPosition1.value = this.positionRT[1].texture; mouseShader.uniforms.order.value = 1; renderer.setRenderTarget(this.targetRT[0]); renderer.render(this.fboScene, this.fboCamera); mouseShader.uniforms.order.value = -1; renderer.setRenderTarget(this.targetRT[1]); renderer.render(this.fboScene, this.fboCamera); let tmp = this.positionRT[0]; this.positionRT[0] = this.targetRT[0]; this.targetRT[0] = tmp; tmp = this.positionRT[1]; this.positionRT[1] = this.targetRT[1]; this.targetRT[1] = tmp; } computeVertexNormals(renderer) { const normalsShader = this.mainController.materials.normalsShader; this.fboMesh.material = normalsShader; normalsShader.uniforms.tSize.value.copy(this.tSize); normalsShader.uniforms.tPosition0.value = this.positionRT[0].texture; normalsShader.uniforms.tPosition1.value = this.positionRT[1].texture; normalsShader.uniforms.tAdjacentsA.value = this.adjacentsRT[0].texture; normalsShader.uniforms.tAdjacentsB.value = this.adjacentsRT[1].texture; renderer.setRenderTarget(this.normalsRT); renderer.render(this.fboScene, this.fboCamera); } } function createRenderTarget(resolution) { return new WebGLRenderTarget(resolution.x, resolution.y, { wrapS: ClampToEdgeWrapping, wrapT: ClampToEdgeWrapping, minFilter: NearestFilter, magFilter: NearestFilter, format: RGBAFormat, type: HalfFloatType, // depthTest: false, // depthWrite: false, depthBuffer: false, stencilBuffer: false }); }