提交 c2e53b98 编写于 作者: N Nicolas Maréchal

compute lightprobe from a CubeRenderTarget


fix broken example


convertColorToLinear do noting for LinearEncoding


fix lightprobe generator and example


fix wrong variable name
上级 a6b2e376
......@@ -61,6 +61,7 @@ var files = {
"webgl_layers",
"webgl_lensflares",
"webgl_lightprobe",
"webgl_lightprobe_cubecamera",
"webgl_lights_hemisphere",
"webgl_lights_physical",
"webgl_lights_pointlights",
......
......@@ -50,7 +50,7 @@ THREE.LightProbeGenerator = {
color.setRGB( data[ i ] / 255, data[ i + 1 ] / 255, data[ i + 2 ] / 255 );
// convert to linear color space
color.copySRGBToLinear( color );
convertColorToLinear( color, cubeTexture.encoding );
// pixel coordinate on unit cube
......@@ -116,6 +116,128 @@ THREE.LightProbeGenerator = {
return new THREE.LightProbe( sh );
},
fromRenderTargetCube: function ( renderer, renderTargetCube ) {
// The renderTarget must be set to RGBA in order to make readRenderTargetPixels works
var norm, lengthSq, weight, totalWeight = 0;
var coord = new THREE.Vector3();
var dir = new THREE.Vector3();
var color = new THREE.Color();
var shBasis = [ 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
var sh = new THREE.SphericalHarmonics3();
var shCoefficients = sh.coefficients;
for ( var faceIndex = 0; faceIndex < 6; faceIndex ++ ) {
var imageWidth = renderTargetCube.width; // assumed to be square
var data = new Uint8Array( imageWidth * imageWidth * 4 );
renderer.readRenderTargetPixels( renderTargetCube, 0, 0, imageWidth, imageWidth, data, faceIndex );
var pixelSize = 2 / imageWidth;
for ( var i = 0, il = data.length; i < il; i += 4 ) { // RGBA assumed
// pixel color
color.setRGB( data[ i ] / 255, data[ i + 1 ] / 255, data[ i + 2 ] / 255 );
// convert to linear color space
convertColorToLinear( color, renderTargetCube.texture.encoding );
// pixel coordinate on unit cube
var pixelIndex = i / 4;
var col = - 1 + ( pixelIndex % imageWidth + 0.5 ) * pixelSize;
var row = 1 - ( Math.floor( pixelIndex / imageWidth ) + 0.5 ) * pixelSize;
switch ( faceIndex ) {
case 0: coord.set( 1, row, - col ); break;
case 1: coord.set( - 1, row, col ); break;
case 2: coord.set( col, 1, - row ); break;
case 3: coord.set( col, - 1, row ); break;
case 4: coord.set( col, row, 1 ); break;
case 5: coord.set( - col, row, - 1 ); break;
}
// weight assigned to this pixel
lengthSq = coord.lengthSq();
weight = 4 / ( Math.sqrt( lengthSq ) * lengthSq );
totalWeight += weight;
// direction vector to this pixel
dir.copy( coord ).normalize();
// evaluate SH basis functions in direction dir
THREE.SphericalHarmonics3.getBasisAt( dir, shBasis );
// accummuulate
for ( var j = 0; j < 9; j ++ ) {
shCoefficients[ j ].x += shBasis[ j ] * color.r * weight;
shCoefficients[ j ].y += shBasis[ j ] * color.g * weight;
shCoefficients[ j ].z += shBasis[ j ] * color.b * weight;
}
}
}
// normalize
norm = ( 4 * Math.PI ) / totalWeight;
for ( var j = 0; j < 9; j ++ ) {
shCoefficients[ j ].x *= norm;
shCoefficients[ j ].y *= norm;
shCoefficients[ j ].z *= norm;
}
return new THREE.LightProbe( sh );
}
};
var convertColorToLinear = function ( color, encoding ) {
switch ( encoding ) {
case THREE.sRGBEncoding:
color.convertSRGBToLinear();
break;
case THREE.LinearEncoding:
break;
default:
console.warn( 'WARNING: LightProbeGenerator convertColorToLinear() encountered an unsupported encoding.' );
break;
}
return color;
};
import {
CubeTexture,
LightProbe
CubeTexture,
LightProbe,
WebGLRenderer,
WebGLRenderTargetCube,
} from '../../../src/Three';
export namespace LightProbeGenerator {
export function fromCubeTexture( cubeTexture: CubeTexture ): LightProbe;
export function fromCubeTexture(cubeTexture: CubeTexture): LightProbe;
export function fromRenderTargetCube(renderer: WebGLRenderer, renderTargetCube: WebGLRenderTargetCube): LightProbe;
}
......@@ -5,8 +5,10 @@
import {
Color,
LightProbe,
LinearEncoding,
SphericalHarmonics3,
Vector3
Vector3,
sRGBEncoding
} from "../../../build/three.module.js";
var LightProbeGenerator = {
......@@ -57,7 +59,7 @@ var LightProbeGenerator = {
color.setRGB( data[ i ] / 255, data[ i + 1 ] / 255, data[ i + 2 ] / 255 );
// convert to linear color space
color.copySRGBToLinear( color );
convertColorToLinear( color, cubeTexture.encoding );
// pixel coordinate on unit cube
......@@ -123,8 +125,130 @@ var LightProbeGenerator = {
return new LightProbe( sh );
},
fromRenderTargetCube: function ( renderer, renderTargetCube ) {
// The renderTarget must be set to RGBA in order to make readRenderTargetPixels works
var norm, lengthSq, weight, totalWeight = 0;
var coord = new Vector3();
var dir = new Vector3();
var color = new Color();
var shBasis = [ 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
var sh = new SphericalHarmonics3();
var shCoefficients = sh.coefficients;
for ( var faceIndex = 0; faceIndex < 6; faceIndex ++ ) {
var imageWidth = renderTargetCube.width; // assumed to be square
var data = new Uint8Array( imageWidth * imageWidth * 4 );
renderer.readRenderTargetPixels( renderTargetCube, 0, 0, imageWidth, imageWidth, data, faceIndex );
var pixelSize = 2 / imageWidth;
for ( var i = 0, il = data.length; i < il; i += 4 ) { // RGBA assumed
// pixel color
color.setRGB( data[ i ] / 255, data[ i + 1 ] / 255, data[ i + 2 ] / 255 );
// convert to linear color space
convertColorToLinear( color, renderTargetCube.texture.encoding );
// pixel coordinate on unit cube
var pixelIndex = i / 4;
var col = - 1 + ( pixelIndex % imageWidth + 0.5 ) * pixelSize;
var row = 1 - ( Math.floor( pixelIndex / imageWidth ) + 0.5 ) * pixelSize;
switch ( faceIndex ) {
case 0: coord.set( 1, row, - col ); break;
case 1: coord.set( - 1, row, col ); break;
case 2: coord.set( col, 1, - row ); break;
case 3: coord.set( col, - 1, row ); break;
case 4: coord.set( col, row, 1 ); break;
case 5: coord.set( - col, row, - 1 ); break;
}
// weight assigned to this pixel
lengthSq = coord.lengthSq();
weight = 4 / ( Math.sqrt( lengthSq ) * lengthSq );
totalWeight += weight;
// direction vector to this pixel
dir.copy( coord ).normalize();
// evaluate SH basis functions in direction dir
SphericalHarmonics3.getBasisAt( dir, shBasis );
// accummuulate
for ( var j = 0; j < 9; j ++ ) {
shCoefficients[ j ].x += shBasis[ j ] * color.r * weight;
shCoefficients[ j ].y += shBasis[ j ] * color.g * weight;
shCoefficients[ j ].z += shBasis[ j ] * color.b * weight;
}
}
}
// normalize
norm = ( 4 * Math.PI ) / totalWeight;
for ( var j = 0; j < 9; j ++ ) {
shCoefficients[ j ].x *= norm;
shCoefficients[ j ].y *= norm;
shCoefficients[ j ].z *= norm;
}
return new LightProbe( sh );
}
};
var convertColorToLinear = function ( color, encoding ) {
switch ( encoding ) {
case sRGBEncoding:
color.convertSRGBToLinear();
break;
case LinearEncoding:
break;
default:
console.warn( 'WARNING: LightProbeGenerator convertColorToLinear() encountered an unsupported encoding.' );
break;
}
return color;
};
export { LightProbeGenerator };
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - light probe from cubeCamera</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link type="text/css" rel="stylesheet" href="main.css">
</head>
<body>
<div id="info">
<a href="http://threejs.org" target="_blank" rel="noopener">three.js</a> webgl - light probe from cubeCamera
</div>
<script type="module">
import * as THREE from '../build/three.module.js';
import { GUI } from './jsm/libs/dat.gui.module.js';
import { OrbitControls } from './jsm/controls/OrbitControls.js';
import { LightProbeGenerator } from './jsm/lights/LightProbeGenerator.js';
var renderer, scene, camera, cubeCamera;
var lightProbe;
init();
function init() {
// renderer
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
// gamma
renderer.gammaOutput = true;
renderer.gammaFactor = 2.2; // approximate sRGB
// scene
scene = new THREE.Scene();
// camera
camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.set( 0, 0, 30 );
cubeCamera = new THREE.CubeCamera( 1, 1000, 256, { format: THREE.RGBAFormat, magFilter: THREE.LinearFilter, minFilter: THREE.LinearFilter } );
//Since gamma is applied during rendering, the cubeCamera renderTarget texture encoding must be sRGBEncoding
cubeCamera.renderTarget.texture.encoding = THREE.sRGBEncoding;
// controls
var controls = new OrbitControls( camera, renderer.domElement );
controls.addEventListener( 'change', render );
controls.minDistance = 10;
controls.maxDistance = 50;
controls.enablePan = false;
// probe
lightProbe = new THREE.LightProbe();
scene.add( lightProbe );
// envmap
var genCubeUrls = function ( prefix, postfix ) {
return [
prefix + 'px' + postfix, prefix + 'nx' + postfix,
prefix + 'py' + postfix, prefix + 'ny' + postfix,
prefix + 'pz' + postfix, prefix + 'nz' + postfix
];
};
var urls = genCubeUrls( 'textures/cube/pisa/', '.png' );
new THREE.CubeTextureLoader().load( urls, function ( cubeTexture ) {
cubeTexture.encoding = THREE.sRGBEncoding;
scene.background = cubeTexture;
cubeCamera.update( renderer, scene );
lightProbe.copy( LightProbeGenerator.fromRenderTargetCube( renderer, cubeCamera.renderTarget ) );
scene.add( new THREE.LightProbeHelper(lightProbe, 5) );
render();
} );
// listener
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
renderer.setSize( window.innerWidth, window.innerHeight );
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
render();
}
function render() {
renderer.render( scene, camera );
}
</script>
</body>
</html>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册