playcanvas
Version:
Open-source WebGL/WebGPU 3D engine for the web
84 lines (83 loc) • 2.67 kB
JavaScript
import { FloatPacking } from "../core/math/float-packing.js";
import { Texture } from "../platform/graphics/texture.js";
import { DeviceCache } from "../platform/graphics/device-cache.js";
import {
ADDRESS_CLAMP_TO_EDGE,
FILTER_LINEAR,
FILTER_NEAREST,
PIXELFORMAT_RGBA16F,
TEXTURETYPE_DEFAULT
} from "../platform/graphics/constants.js";
class AreaLightCacheEntry {
constructor(texture0, texture1) {
this.texture0 = texture0;
this.texture1 = texture1;
}
destroy() {
this.texture0?.destroy();
this.texture1?.destroy();
}
}
const deviceCache = new DeviceCache();
class AreaLightLuts {
static createTexture(device, format, size, postfix = "") {
const tex = new Texture(device, {
name: `AreaLightLUT${postfix}`,
width: size,
height: size,
format,
addressU: ADDRESS_CLAMP_TO_EDGE,
addressV: ADDRESS_CLAMP_TO_EDGE,
type: TEXTURETYPE_DEFAULT,
magFilter: FILTER_LINEAR,
minFilter: FILTER_NEAREST,
anisotropy: 1,
mipmaps: false
});
return tex;
}
static applyTextures(device, texture1, texture2) {
deviceCache.remove(device);
deviceCache.get(device, () => {
return new AreaLightCacheEntry(texture1, texture1 === texture2 ? null : texture2);
});
device.scope.resolve("areaLightsLutTex1").setValue(texture1);
device.scope.resolve("areaLightsLutTex2").setValue(texture2);
}
// placeholder LUT textures for area light
static createPlaceholder(device) {
const texture = AreaLightLuts.createTexture(device, PIXELFORMAT_RGBA16F, 2, "placeholder");
const pixels = texture.lock();
pixels.fill(0);
texture.unlock();
AreaLightLuts.applyTextures(device, texture, texture);
}
// creates LUT texture used by area lights
static set(device, ltcMat1, ltcMat2) {
function buildTexture(device2, data, format) {
const texture = AreaLightLuts.createTexture(device2, format, 64);
texture.lock().set(data);
texture.unlock();
return texture;
}
function convertToHalfFloat(data) {
const count = data.length;
const ret = new Uint16Array(count);
const float2Half = FloatPacking.float2Half;
for (let i = 0; i < count; i++) {
ret[i] = float2Half(data[i]);
}
return ret;
}
const srcData1 = ltcMat1;
const srcData2 = ltcMat2;
const data1 = convertToHalfFloat(srcData1);
const data2 = convertToHalfFloat(srcData2);
const tex1 = buildTexture(device, data1, PIXELFORMAT_RGBA16F);
const tex2 = buildTexture(device, data2, PIXELFORMAT_RGBA16F);
AreaLightLuts.applyTextures(device, tex1, tex2);
}
}
export {
AreaLightLuts
};