Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/files.json
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@
"webgpu_depth_texture",
"webgpu_display_stereo",
"webgpu_equirectangular",
"webgpu_fog_height",
"webgpu_hdr",
"webgpu_instance_mesh",
"webgpu_instance_path",
Expand Down
Binary file added examples/screenshots/webgpu_fog_height.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
148 changes: 148 additions & 0 deletions examples/webgpu_fog_height.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgpu - height fog</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="example.css">
</head>
<body>

<div id="info" class="invert">
<a href="https://threejs.org/" target="_blank" rel="noopener" class="logo-link"></a>

<div class="title-wrapper">
<a href="https://threejs.org/" target="_blank" rel="noopener">three.js</a><span>Height Fog</span>
</div>

<small>
Exponential Height Fog with TSL.
</small>
</div>

<script type="importmap">
{
"imports": {
"three": "../build/three.webgpu.js",
"three/webgpu": "../build/three.webgpu.js",
"three/tsl": "../build/three.tsl.js",
"three/addons/": "./jsm/"
}
}
</script>

<script type="module">

import * as THREE from 'three/webgpu';
import { exponentialHeightFogFactor, uniform, fog, color } from 'three/tsl';

import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { Inspector } from 'three/addons/inspector/Inspector.js';

let camera, scene, renderer;
let controls;

init();

function init() {

camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 600 );
camera.position.set( 20, 10, 25 );

scene = new THREE.Scene();

// height fog

const density = uniform( 0.04 );
const height = uniform( 2 );

const fogFactor = exponentialHeightFogFactor( density, height );

scene.fogNode = fog( color( 0xffdfc1 ), fogFactor );
scene.backgroundNode = color( 0xffdfc1 );

// meshes

const geometry = new THREE.BoxGeometry( 1, 25, 1 );
const material = new THREE.MeshPhongNodeMaterial( { color: 0xcd959a } );

const mesh = new THREE.InstancedMesh( geometry, material, 100 );
mesh.position.y = - 10;
scene.add( mesh );

const dummy = new THREE.Object3D();

let index = 0;

for ( let i = 0; i < 10; i ++ ) {

for ( let j = 0; j < 10; j ++ ) {

dummy.position.x = - 18 + ( i * 4 );
dummy.position.z = - 18 + ( j * 4 );

dummy.updateMatrix();

mesh.setMatrixAt( index ++, dummy.matrix );

}

}

// lights

const directionalLight = new THREE.DirectionalLight( 0xffc0cb, 2 );
directionalLight.position.set( - 10, 10, 10 );
scene.add( directionalLight );

const ambientLight = new THREE.AmbientLight( 0xcccccc );
scene.add( ambientLight );

// renderer

renderer = new THREE.WebGPURenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setAnimationLoop( animate );
renderer.inspector = new Inspector();
document.body.appendChild( renderer.domElement );

// gui

const gui = renderer.inspector.createParameters( 'Fog Settings' );

gui.add( density, 'value', 0.001, 0.1 ).step( 0.0001 ).name( 'Density' );
gui.add( height, 'value', - 5, 5 ).name( 'Height' );

// controls

controls = new OrbitControls( camera, renderer.domElement );
controls.minDistance = 7;
controls.maxDistance = 100;
controls.maxPolarAngle = Math.PI / 2;
controls.enableDamping = true;

window.addEventListener( 'resize', resize );

}

function resize() {

camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();

renderer.setSize( window.innerWidth, window.innerHeight );

}

function animate() {

controls.update();

renderer.render( scene, camera );

}

</script>
</body>
</html>
1 change: 1 addition & 0 deletions src/Three.TSL.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ export const equal = TSL.equal;
export const equirectUV = TSL.equirectUV;
export const exp = TSL.exp;
export const exp2 = TSL.exp2;
export const exponentialHeightFogFactor = TSL.exponentialHeightFogFactor;
export const expression = TSL.expression;
export const faceDirection = TSL.faceDirection;
export const faceForward = TSL.faceForward;
Expand Down
21 changes: 20 additions & 1 deletion src/nodes/fog/Fog.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { positionView } from '../accessors/Position.js';
import { positionView, positionWorld } from '../accessors/Position.js';
import { smoothstep } from '../math/MathNode.js';
import { Fn, output, vec4 } from '../tsl/TSLBase.js';

Expand Down Expand Up @@ -62,6 +62,25 @@ export const densityFogFactor = Fn( ( [ density ], builder ) => {

} );

/**
* Constructs a new height fog factor node. This fog factor requires a Y-up coordinate system.
*
* @tsl
* @function
* @param {Node} density - Defines the fog density.
* @param {Node} height - The height threshold in world space. Everything below this y-coordinate is affected by fog.
*/
export const exponentialHeightFogFactor = Fn( ( [ density, height ], builder ) => {

const viewZ = getViewZNode( builder );

const distance = height.sub( positionWorld.y ).max( 0 ).toConst();
const m = distance.mul( viewZ ).toConst();

return density.mul( density, m, m ).negate().exp().oneMinus();

} );

/**
* This class can be used to configure a fog for the scene.
* Nodes of this type are assigned to `Scene.fogNode`.
Expand Down