@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
142 lines (98 loc) • 4.28 kB
JavaScript
import { sh3_basis_at } from "../../../core/geom/3d/sphere/harmonics/sh3_basis_at.js";
import { sh3_dering_optimize_positive } from "../../../core/geom/3d/sphere/harmonics/sh3_dering_optimize_positive.js";
import { sh3_vector_accumulate } from "../../../core/geom/3d/sphere/harmonics/sh3_vector_accumulate.js";
import { vector_scale_array } from "../../../core/geom/vec/vector_scale_array.js";
import { v3_length_sqr } from "../../../core/geom/vec3/v3_length_sqr.js";
const scratch_color = new Float32Array(3);
/**
*
* @param {Uint8Array} data
* @param {THREE.WebGLRenderer} renderer
* @param {THREE.WebGLCubeRenderTarget} cubeRenderTarget
* @return {Float64Array}
*/
export function fromCubeRenderTarget(
data,
renderer,
cubeRenderTarget
) {
// The renderTarget must be set to RGBA in order to make readRenderTargetPixels works
let total_weight = 0;
const __shared_buffer = new ArrayBuffer((27 + 9) * 8);
const sh_basis = new Float64Array(__shared_buffer, 0, 9);
const coefficients = new Float64Array(__shared_buffer, 9 * 8, 27);
const image_size = cubeRenderTarget.width;
const pixel_size = 2 / image_size;
let normal_x = 0, normal_y = 0, normal_z = 0;
for (let faceIndex = 0; faceIndex < 6; faceIndex++) {
renderer.readRenderTargetPixels(cubeRenderTarget, 0, 0, image_size, image_size, data, faceIndex);
// RGBA assumed
for (let i = 0, il = data.length; i < il; i += 4) {
// pixel coordinate on unit cube
const pixelIndex = i / 4;
const col = -1 + (pixelIndex % image_size + 0.5) * pixel_size;
const row = 1 - (Math.floor(pixelIndex / image_size) + 0.5) * pixel_size;
switch (faceIndex) {
case 0:
normal_x = 1;
normal_y = row;
normal_z = -col;
break;
case 1:
normal_x = -1;
normal_y = row;
normal_z = col;
break;
case 2:
normal_x = col;
normal_y = 1;
normal_z = -row;
break;
case 3:
normal_x = col;
normal_y = -1;
normal_z = row;
break;
case 4:
normal_x = col;
normal_y = row;
normal_z = 1;
break;
case 5:
normal_x = -col;
normal_y = row;
normal_z = -1;
break;
}
// weight assigned to this pixel
const length_squared = v3_length_sqr(normal_x, normal_y, normal_z);
const length = Math.sqrt(length_squared);
const weight = 4 / (length * length_squared);
total_weight += weight;
// direction vector to this pixel
normal_x /= length;
normal_y /= length;
normal_z /= length;
// evaluate SH basis functions in direction dir
sh3_basis_at(normal_x, normal_y, normal_z, sh_basis);
// pixel color, already in linear space so no sRGB->Linear conversion necessary
// 0.003921 constant value is 1/255, a conversion value from UINT8 to normalized float
const weight_conv = weight * 0.00392156862745098;
scratch_color[0] = data[i] * weight_conv;
scratch_color[1] = data[i + 1] * weight_conv;
scratch_color[2] = data[i + 2] * weight_conv;
// accumulate
sh3_vector_accumulate(
coefficients, 0,
sh_basis, 0,
scratch_color, 0,
3
);
}
}
// normalize
const norm = (4 * Math.PI) / total_weight;
vector_scale_array(coefficients, 0, coefficients, 0, 27, norm);
sh3_dering_optimize_positive(coefficients, 0, coefficients, 0, 3);
return coefficients;
}