playcanvas
Version:
Open-source WebGL/WebGPU 3D engine for the web
76 lines (73 loc) • 2.57 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 { FILTER_NEAREST, FILTER_LINEAR, TEXTURETYPE_DEFAULT, ADDRESS_CLAMP_TO_EDGE, PIXELFORMAT_RGBA16F } from '../platform/graphics/constants.js';
class AreaLightCacheEntry {
destroy() {
this.texture0?.destroy();
this.texture1?.destroy();
}
constructor(texture0, texture1){
this.texture0 = texture0;
this.texture1 = texture1;
}
}
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: 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);
}
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);
}
static set(device, ltcMat1, ltcMat2) {
function buildTexture(device, data, format) {
const texture = AreaLightLuts.createTexture(device, 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 };