UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

142 lines (98 loc) 4.28 kB
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; }