3D Gaussian on Cuboid

by Matt

HTML

<base href="https://rawcdn.githack.com/mrdoob/three.js/r156/examples/" />
<script async src="https://cdn.jsdelivr.net/npm/[email protected]/dist/es-module-shims.js"></script>
<script type="importmap">
	{
		"imports": {
			"three": "https://cdn.jsdelivr.net/npm/[email protected]/build/three.module.js",
			"three/addons/": "https://cdn.jsdelivr.net/npm/[email protected]/examples/jsm/",
			"lil-gui": "https://cdn.jsdelivr.net/npm/[email protected]/dist/lil-gui.esm.min.js"
		}
	}
</script>

CSS

canvas {
	position: fixed;
	inset: 0;
}

JavaScript

import * as THREE from 'three'
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
import { TransformControls } from 'three/addons/controls/TransformControls.js'
import { GUI } from 'lil-gui'

let scene, camera, renderer
let meshGaussian, meshWireframe, orbit, control, clock
let params

/**
 * Supporting example for https://twitter.com/the_ross_man/status/1714628350809895172
 * by Matt Rossman based on explanation by Hamish Todd
 */


const vertexShader = `
varying vec3 vPos;
varying vec3 vCamera;

void main() {
  
  // 1. vertex position in model space
  
  vPos = position;
  
  
  // 2. camera position in model space
  
  mat4 modelMatrixInverse = inverse(modelMatrix);
  vCamera = (modelMatrixInverse * vec4(cameraPosition, 1.0)).xyz;
  
	gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`

const fragmentShader = `
varying vec3 vPos;
varying vec3 vCamera;

/**
 * Finds shortest distance from point "p" to the line spanned by "x1" and "x2"
 * 
 * Reference: https://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html
 */
float pointToLineDistance(vec3 p, vec3 x1, vec3 x2) {
  
  return length( cross( p - x1, p - x2 ) ) / length( x2 - x1 );
  
}

float gaussian(float x) {

	return exp( -0.5 * x * x );

}

void main() {

  // 1. find distance from camera ray to Gaussian center
  
  float radius = pointToLineDistance( vec3(0.0), vCamera, vPos );
  
  
  // 2. plug this distance into 1D Gaussian equation
  
  float alpha = gaussian( radius );
  
  
	gl_FragColor = vec4( vec3(1.0), alpha );
  
  #include <tonemapping_fragment>
  #include <colorspace_fragment>
  
}
`

async function init() {

	params = {
    wireframe: false
	}
	
	scene = new THREE.Scene()
	scene.background = new THREE.Color('black')

	camera = new THREE.PerspectiveCamera(75, undefined, 0.01, 1000)
	camera.position.set(5,5,5)
	
	clock = new THREE.Clock()

	const directionalLight = new THREE.DirectionalLight('white',...