@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.
150 lines • 6.19 kB
JavaScript
import { Lerp } from "../../Maths/math.scalar.functions.js";
function lineToArray(line) {
return line
.split(" ")
.filter((x) => x !== "")
.map((x) => parseFloat(x));
}
function readArray(dataPointer, count, targetArray) {
while (targetArray.length !== count) {
const line = lineToArray(dataPointer.lines[dataPointer.index++]);
targetArray.push(...line);
}
}
function interpolateCandelaValues(data, phi, theta) {
let phiIndex = 0;
let thetaIndex = 0;
let startTheta = 0;
let endTheta = 0;
let startPhi = 0;
let endPhi = 0;
// Check if the angle is outside the range
for (let index = 0; index < data.numberOfHorizontalAngles - 1; index++) {
if (theta < data.horizontalAngles[index + 1] || index === data.numberOfHorizontalAngles - 2) {
thetaIndex = index;
startTheta = data.horizontalAngles[index];
endTheta = data.horizontalAngles[index + 1];
break;
}
}
for (let index = 0; index < data.numberOfVerticalAngles - 1; index++) {
if (phi < data.verticalAngles[index + 1] || index === data.numberOfVerticalAngles - 2) {
phiIndex = index;
startPhi = data.verticalAngles[index];
endPhi = data.verticalAngles[index + 1];
break;
}
}
const deltaTheta = endTheta - startTheta;
const deltaPhi = endPhi - startPhi;
if (deltaPhi === 0) {
return 0;
}
// Interpolate
const t1 = deltaTheta === 0 ? 0 : (theta - startTheta) / deltaTheta;
const t2 = (phi - startPhi) / deltaPhi;
const nextThetaIndex = deltaTheta === 0 ? thetaIndex : thetaIndex + 1;
const v1 = Lerp(data.candelaValues[thetaIndex][phiIndex], data.candelaValues[nextThetaIndex][phiIndex], t1);
const v2 = Lerp(data.candelaValues[thetaIndex][phiIndex + 1], data.candelaValues[nextThetaIndex][phiIndex + 1], t1);
const v = Lerp(v1, v2, t2);
return v;
}
/**
* Generates IES data buffer from a string representing the IES data.
* @param uint8Array defines the IES data
* @returns the IES data buffer
* @see https://ieslibrary.com/browse
* @see https://playground.babylonjs.com/#UQGPDT#1
*/
export function LoadIESData(uint8Array) {
const decoder = new TextDecoder("utf-8");
const source = decoder.decode(uint8Array);
// Read data
const dataPointer = {
lines: source.split("\n"),
index: 0,
};
const data = { version: dataPointer.lines[0], candelaValues: [], horizontalAngles: [], verticalAngles: [], numberOfHorizontalAngles: 0, numberOfVerticalAngles: 0 };
// Skip metadata
dataPointer.index = 1;
while (dataPointer.lines.length > 0 && !dataPointer.lines[dataPointer.index].includes("TILT=")) {
dataPointer.index++;
}
// Process tilt data?
if (dataPointer.lines[dataPointer.index].includes("INCLUDE")) {
// Not supported yet as I did not manage to find an example :)
}
dataPointer.index++;
// Header
const header = lineToArray(dataPointer.lines[dataPointer.index++]);
data.numberOfLights = header[0];
data.lumensPerLamp = header[1];
data.candelaMultiplier = header[2];
data.numberOfVerticalAngles = header[3];
data.numberOfHorizontalAngles = header[4];
data.photometricType = header[5]; // We ignore cylindrical type for now. Will add support later if needed
data.unitsType = header[6];
data.width = header[7];
data.length = header[8];
data.height = header[9];
// Additional data
const additionalData = lineToArray(dataPointer.lines[dataPointer.index++]);
data.ballastFactor = additionalData[0];
data.fileGenerationType = additionalData[1];
data.inputWatts = additionalData[2];
// Prepare arrays
for (let index = 0; index < data.numberOfHorizontalAngles; index++) {
data.candelaValues[index] = [];
}
// Vertical angles
readArray(dataPointer, data.numberOfVerticalAngles, data.verticalAngles);
// Horizontal angles
readArray(dataPointer, data.numberOfHorizontalAngles, data.horizontalAngles);
// Candela values
for (let index = 0; index < data.numberOfHorizontalAngles; index++) {
readArray(dataPointer, data.numberOfVerticalAngles, data.candelaValues[index]);
}
// Evaluate candela values
let maxCandela = -1;
for (let index = 0; index < data.numberOfHorizontalAngles; index++) {
for (let subIndex = 0; subIndex < data.numberOfVerticalAngles; subIndex++) {
data.candelaValues[index][subIndex] *= data.candelaValues[index][subIndex] * data.candelaMultiplier * data.ballastFactor * data.fileGenerationType;
maxCandela = Math.max(maxCandela, data.candelaValues[index][subIndex]);
}
}
// Normalize candela values
if (maxCandela > 0) {
for (let index = 0; index < data.numberOfHorizontalAngles; index++) {
for (let subIndex = 0; subIndex < data.numberOfVerticalAngles; subIndex++) {
data.candelaValues[index][subIndex] /= maxCandela;
}
}
}
// Create the cylindrical texture
const height = 180;
const width = height * 2;
const size = width * height;
const arrayBuffer = new Float32Array(width * height);
// Fill the texture
const startTheta = data.horizontalAngles[0];
const endTheta = data.horizontalAngles[data.numberOfHorizontalAngles - 1];
for (let index = 0; index < size; index++) {
let theta = index % width;
const phi = Math.floor(index / width);
// Symmetry
if (endTheta - startTheta !== 0 && (theta < startTheta || theta >= endTheta)) {
theta %= endTheta * 2;
if (theta > endTheta) {
theta = endTheta * 2 - theta;
}
}
arrayBuffer[phi + theta * height] = interpolateCandelaValues(data, phi, theta);
}
// So far we only need the first half of the first row of the texture as we only support IES for spot light. We can add support for other types later.
return {
width: width / 2,
height: 1,
data: arrayBuffer,
};
}
//# sourceMappingURL=iesLoader.js.map