@babylonjs/core
Version:
Getting started? Play directly with the Babylon.js API using our [playground](https://playground.babylonjs.com/). It also contains a lot of samples to learn how to use it.
98 lines • 4 kB
JavaScript
import { Matrix, Vector3 } from "../Maths/math.vector.js";
import { TextureTools } from "../Misc/textureTools.js";
const FlowVector = new Vector3(0, 0, 0);
const ScaledFlowVector = new Vector3(0, 0, 0);
const ScreenPos = new Vector3(0, 0, 0);
/**
* Class used to represent a particle flow map.
* #5DM02T#7
* GPUParts: #5DM02T#12 (webgl2)
* GPUParts: #5DM02T#13 (webgpu)
*/
export class FlowMap {
/**
* Create a new flow map.
* @param width defines the width of the flow map
* @param height defines the height of the flow map
* @param data defines the data of the flow map
*/
constructor(width, height, data) {
this.width = width;
this.height = height;
this.data = data;
}
processFlowable(flowable, strength = 1, flowMapSamplePosOrTransformationMatrix) {
if (!flowMapSamplePosOrTransformationMatrix) {
return;
}
// Convert world pos to screen pos
if (flowMapSamplePosOrTransformationMatrix instanceof Matrix) {
Vector3.TransformCoordinatesToRef(flowable.position, flowMapSamplePosOrTransformationMatrix, ScreenPos);
}
else {
ScreenPos.x = flowMapSamplePosOrTransformationMatrix.x;
ScreenPos.y = flowMapSamplePosOrTransformationMatrix.y;
ScreenPos.z = flowMapSamplePosOrTransformationMatrix.z;
}
const u = ScreenPos.x * 0.5 + 0.5;
const v = 1.0 - (ScreenPos.y * 0.5 + 0.5);
const x = Math.floor(u * this.width);
const y = Math.floor(v * this.height);
// Clamp
if (x < 0 || x >= this.width || y < 0 || y >= this.height) {
return;
}
const index = (y * this.width + x) * 4;
const r = this.data[index];
const g = this.data[index + 1];
const b = this.data[index + 2];
const a = this.data[index + 3];
const fx = (r / 255.0) * 2.0 - 1.0;
const fy = (g / 255.0) * 2.0 - 1.0;
const fz = (b / 255.0) * 2.0 - 1.0;
const localStrength = a / 255.0;
FlowVector.set(fx, fy, fz);
FlowVector.scaleToRef(strength * localStrength, ScaledFlowVector);
flowable.direction.addInPlace(ScaledFlowVector); // Update IFlowable velocity
}
/** @internal */
_processParticle(particle, strength = 1, matrix) {
this.processFlowable(particle, strength, matrix);
}
/**
* Creates a FlowMap from a url.
* @param url The url of the image to load
* @returns a promise that resolves to a FlowMap object
*/
static async FromUrlAsync(url) {
return await new Promise((resolve, reject) => {
const flowCanvas = document.createElement("canvas");
const flowCtx = flowCanvas.getContext("2d");
let flowImageData = null;
const flowMapImage = new Image();
flowMapImage.crossOrigin = "anonymous"; // If loading from another domain
flowMapImage.src = url;
flowMapImage.onerror = (e) => {
reject(new Error(`Failed to load image: ${url} : ${e}`));
};
flowMapImage.onload = () => {
flowCanvas.width = flowMapImage.width;
flowCanvas.height = flowMapImage.height;
flowCtx.drawImage(flowMapImage, 0, 0);
flowImageData = flowCtx.getImageData(0, 0, flowCanvas.width, flowCanvas.height);
resolve(new FlowMap(flowCanvas.width, flowCanvas.height, flowImageData.data));
};
});
}
/**
* Load from a texture
* @param texture defines the source texture
* @returns a promise fulfilled when image data is loaded
*/
static async ExtractFromTextureAsync(texture) {
const data = await TextureTools.GetTextureDataAsync(texture);
const { width, height } = texture.getSize();
return new FlowMap(width, height, new Uint8ClampedArray(data));
}
}
//# sourceMappingURL=flowMap.js.map