Skip to content

Commit

Permalink
🎛 Use lil-gui
Browse files Browse the repository at this point in the history
marcofugaro committed Jan 18, 2023
1 parent 2fcdf47 commit 2db23b1
Showing 20 changed files with 368 additions and 577 deletions.
1 change: 1 addition & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@ module.exports = {
env: {
browser: true,
node: true,
es6: true,
},
extends: [
'eslint:recommended',
6 changes: 2 additions & 4 deletions .github/workflows/deploy-github-pages.yml
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@ on:
- master

jobs:
build:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout repo
@@ -16,9 +16,7 @@ jobs:
uses: actions/setup-node@v3
with:
node-version: 18

- name: Cache node_modules
uses: c-hive/gha-yarn-cache@v2
cache: 'yarn'

- name: Install Dependencies
run: yarn
84 changes: 51 additions & 33 deletions README.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion esbuild.js
Original file line number Diff line number Diff line change
@@ -38,7 +38,7 @@ const result = await esbuild
.build({
entryPoints: ['src/index.js'],
bundle: true,
format: 'iife',
format: 'esm',
logLevel: 'silent', // sssh...
legalComments: 'none', // don't include licenses txt file
sourcemap: true,
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -22,10 +22,9 @@
"dependencies": {
"cannon-es": "^0.20.0",
"cannon-es-debugger": "^1.0.0",
"controls-gui": "^2.0.0",
"controls-state": "^2.0.0",
"detect-gpu": "^5.0.4",
"image-promise": "^7.0.1",
"lil-gui": "^0.17.0",
"lodash-es": "^4.17.21",
"mp4-wasm": "marcofugaro/mp4-wasm#build-embedded",
"p-map": "^5.5.0",
2 changes: 1 addition & 1 deletion public/index.html
Original file line number Diff line number Diff line change
@@ -11,6 +11,6 @@
</head>
<body>
<canvas id="app"></canvas>
<script src="app.js"></script>
<script type="module" src="app.js"></script>
</body>
</html>
60 changes: 24 additions & 36 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@ import WebGLApp from './utils/WebGLApp'
import assets from './utils/AssetManager'
import Suzanne from './scene/Suzanne'
import { addNaturalLight } from './scene/lights'
import { addScreenshotButton, addRecordButton } from './scene/screenshot-record-buttons'
import { addScreenshotButton, addRecordButton } from './screenshot-record-buttons'

// true if the url has the `?debug` parameter, otherwise false
window.DEBUG = window.location.search.includes('debug')
@@ -23,20 +23,8 @@ const webgl = new WebGLApp({
showFps: window.DEBUG,
// enable OrbitControls
orbitControls: window.DEBUG,
// Add the controls pane inputs
controls: {
roughness: 0.5,
movement: {
speed: {
value: 1.5,
max: 100,
scale: 'exp',
},
frequency: { value: 0.5, max: 5 },
amplitude: { value: 0.7, max: 2 },
},
},
hideControls: !window.DEBUG,
// show the GUI
gui: window.DEBUG,
// enable cannon-es
// world: new CANNON.World(),
})
@@ -50,29 +38,29 @@ if (window.DEBUG) {
webgl.canvas.style.visibility = 'hidden'

// load any queued assets
assets.load({ renderer: webgl.renderer }).then(() => {
// add any "WebGL components" here...
// append them to the scene so you can
// use them from other components easily
webgl.scene.suzanne = new Suzanne(webgl)
webgl.scene.add(webgl.scene.suzanne)
await assets.load({ renderer: webgl.renderer })

// lights and other scene related stuff
addNaturalLight(webgl)
// add any "WebGL components" here...
// append them to the scene so you can
// use them from other components easily
webgl.scene.suzanne = new Suzanne(webgl)
webgl.scene.add(webgl.scene.suzanne)

// postprocessing
// add an existing effect from the postprocessing library
webgl.composer.addPass(new EffectPass(webgl.camera, new VignetteEffect()))
// lights and other scene related stuff
addNaturalLight(webgl)

// add the save screenshot and save gif buttons
if (window.DEBUG) {
addScreenshotButton(webgl)
addRecordButton(webgl)
}
// postprocessing
// add an existing effect from the postprocessing library
webgl.composer.addPass(new EffectPass(webgl.camera, new VignetteEffect()))

// show canvas
webgl.canvas.style.visibility = ''
// add the save screenshot and save gif buttons
if (window.DEBUG) {
addScreenshotButton(webgl)
addRecordButton(webgl)
}

// start animation loop
webgl.start()
})
// show canvas
webgl.canvas.style.visibility = ''

// start animation loop
webgl.start()
10 changes: 5 additions & 5 deletions src/scene/Box.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as THREE from 'three'
import { BoxGeometry, Group, Mesh, MeshBasicMaterial } from 'three'

// basic three.js component example

export default class Box extends THREE.Group {
export default class Box extends Group {
constructor(webgl, options = {}) {
super(options)
// these can be used also in other methods
@@ -12,9 +12,9 @@ export default class Box extends THREE.Group {
// destructure and default values like you do in React
const { color = 0x00ff00 } = this.options

const geometry = new THREE.BoxGeometry(1, 1, 1)
const material = new THREE.MeshBasicMaterial({ color, wireframe: true })
this.box = new THREE.Mesh(geometry, material)
const geometry = new BoxGeometry(1, 1, 1)
const material = new MeshBasicMaterial({ color, wireframe: true })
this.box = new Mesh(geometry, material)

// add it to the group,
// later the group will be added to the scene
16 changes: 8 additions & 8 deletions src/scene/CannonSphere.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as THREE from 'three'
import * as CANNON from 'cannon-es'
import { Group, Mesh, MeshStandardMaterial, SphereGeometry } from 'three'
import { Body, Sphere } from 'cannon-es'

// remember to add the body to the CANNON world and
// the mesh to the three.js scene or to some component
@@ -8,8 +8,8 @@ import * as CANNON from 'cannon-es'
// webgl.world.addBody(sphere)
// webgl.scene.add(sphere.mesh)

export default class CannonSphere extends CANNON.Body {
mesh = new THREE.Group()
export default class CannonSphere extends Body {
mesh = new Group()

constructor(webgl, options = {}) {
super(options)
@@ -18,13 +18,13 @@ export default class CannonSphere extends CANNON.Body {

const { radius = 1 } = this.options

this.addShape(new CANNON.Sphere(radius))
this.addShape(new Sphere(radius))

// add corresponding geometry and material
this.mesh.add(
new THREE.Mesh(
new THREE.SphereGeometry(radius, 32, 32),
new THREE.MeshStandardMaterial({ color: Math.random() * 0xffffff })
new Mesh(
new SphereGeometry(radius, 32, 32),
new MeshStandardMaterial({ color: Math.random() * 0xffffff })
)
)

31 changes: 17 additions & 14 deletions src/scene/Suzanne.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import * as THREE from 'three'
import { Group, MeshStandardMaterial, Raycaster, Vector2 } from 'three'
import glsl from 'glslify'
import assets from '../utils/AssetManager'
import { wireValue, wireUniform } from '../utils/Controls'
import { addUniforms, customizeVertexShader } from '../utils/customizeShader'

// elaborated three.js component example
@@ -45,7 +44,7 @@ const hdrKey = assets.queue({
type: 'env-map',
})

export default class Suzanne extends THREE.Group {
export default class Suzanne extends Group {
constructor(webgl, options = {}) {
super(options)
this.webgl = webgl
@@ -55,26 +54,26 @@ export default class Suzanne extends THREE.Group {
const suzanne = suzanneGltf.scene.clone()

const envMap = assets.get(hdrKey)
const material = new THREE.MeshStandardMaterial({
const material = new MeshStandardMaterial({
map: assets.get(albedoKey),
metalnessMap: assets.get(metalnessKey),
roughnessMap: assets.get(roughnessKey),
normalMap: assets.get(normalKey),
normalScale: new THREE.Vector2(2, 2),
normalScale: new Vector2(2, 2),
envMap,
roughness: webgl.controls.roughness,
roughness: 0.5,
metalness: 1,
})
webgl.gui?.addSmart(material, 'roughness')
this.material = material

wireValue(material, () => webgl.controls.roughness)

// add new unifroms and expose current uniforms
addUniforms(material, {
time: { value: 0 },
frequency: wireUniform(material, () => webgl.controls.movement.frequency),
amplitude: wireUniform(material, () => webgl.controls.movement.amplitude),
frequency: { value: 0.5 },
amplitude: { value: 0.7 },
})
webgl.gui?.wireUniforms('movement', material.uniforms, { blacklist: ['time'] })

customizeVertexShader(material, {
head: glsl`
@@ -83,7 +82,7 @@ export default class Suzanne extends THREE.Group {
uniform float amplitude;
// you could import glsl packages like this
// #pragma glslify: noise = require(glsl-noise/simplex/3d)
// #pragma glslify: noise3d = require(glsl-noise/simplex/3d)
`,
main: glsl`
float theta = sin(position.z * frequency + time) * amplitude;
@@ -111,6 +110,10 @@ export default class Suzanne extends THREE.Group {
// make it a little bigger
suzanne.scale.multiplyScalar(1.2)

// incremental speed, we can change it through the GUI
this.speed = 1.5
webgl.gui?.folders.find((f) => f._title === 'movement').addSmart(this, 'speed')

this.add(suzanne)

// set the background as the hdr
@@ -120,11 +123,11 @@ export default class Suzanne extends THREE.Group {
onPointerDown(event, { x, y }) {
// for example, check of we clicked on an
// object with raycasting
const coords = new THREE.Vector2().set(
const coords = new Vector2().set(
(x / this.webgl.width) * 2 - 1,
(-y / this.webgl.height) * 2 + 1
)
const raycaster = new THREE.Raycaster()
const raycaster = new Raycaster()
raycaster.setFromCamera(coords, this.webgl.camera)
const hits = raycaster.intersectObject(this, true)
console.log(hits.length > 0 ? `Hit ${hits[0].object.name}!` : 'No hit')
@@ -133,6 +136,6 @@ export default class Suzanne extends THREE.Group {
}

update(dt, time) {
this.material.uniforms.time.value += dt * this.webgl.controls.movement.speed
this.material.uniforms.time.value += dt * this.speed
}
}
6 changes: 3 additions & 3 deletions src/scene/lights.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import * as THREE from 'three'
import { DirectionalLight, HemisphereLight } from 'three'

// natural hemisphere light from
// https://threejs.org/examples/#webgl_lights_hemisphere
export function addNaturalLight(webgl) {
const hemiLight = new THREE.HemisphereLight(0xffffff, 0xffffff, 0.6)
const hemiLight = new HemisphereLight(0xffffff, 0xffffff, 0.6)
hemiLight.color.setHSL(0.6, 1, 0.6)
hemiLight.groundColor.setHSL(0.095, 1, 0.75)
hemiLight.position.set(0, 50, 0)
webgl.scene.add(hemiLight)

const dirLight = new THREE.DirectionalLight(0xffffff, 1)
const dirLight = new DirectionalLight(0xffffff, 1)
dirLight.color.setHSL(0.1, 1, 0.95)
dirLight.position.set(3, 5, 1)
dirLight.position.multiplyScalar(50)
File renamed without changes.
46 changes: 46 additions & 0 deletions src/utils/AssetManager.js
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@ import omit from 'lodash/omit'
import loadTexture from './loadTexture'
import loadEnvMap from './loadEnvMap'
import loadGLTF from './loadGLTF'
import { mapValues } from 'lodash-es'

class AssetManager {
#queue = []
@@ -42,6 +43,46 @@ class AssetManager {
return url
}

// Add a MeshStandardMaterial to be queued,
// input: { map, metalnessMap, roughnessMap, normalMap, ... }
queueStandardMaterial(maps, options = {}) {
const keys = {}

// These textures are non-color and they don't
// need gamma correction
const linearTextures = [
'pbrMap',
'alphaMap',
'aoMap',
'bumpMap',
'displacementMap',
'lightMap',
'metalnessMap',
'normalMap',
'roughnessMap',
'clearcoatMap',
'clearcoatNormalMap',
'clearcoatRoughnessMap',
'sheenRoughnessMap',
'sheenColorMap',
'specularIntensityMap',
'specularColorMap',
'thicknessMap',
'transmissionMap',
]

Object.keys(maps).forEach((map) => {
keys[map] = this.queue({
url: maps[map],
type: 'texture',
...options,
...(linearTextures.includes(map) && { linear: true }),
})
})

return keys
}

_getQueued(url) {
return this.#queue.find((item) => item.url === url)
}
@@ -74,6 +115,11 @@ class AssetManager {
return this.#loaded[key]
}

// Fetch a loaded MeshStandardMaterial object
getStandardMaterial = (keys) => {
return mapValues(keys, (key) => this.get(key))
}

// Loads a single asset on demand.
async loadSingle({ renderer, ...item }) {
// renderer is used to load textures and env maps,
295 changes: 0 additions & 295 deletions src/utils/Controls.js

This file was deleted.

85 changes: 85 additions & 0 deletions src/utils/ExponentialNumberController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { NumberController } from 'lil-gui'

// Exponential slider for lil-gui.
// Only for numbers > 0

const mapping = (x) => Math.pow(10, x)
const inverseMapping = Math.log10

export class ExponentialNumberController extends NumberController {
updateDisplay() {
super.updateDisplay()

if (this._hasSlider) {
const value = inverseMapping(this.getValue())
const min = inverseMapping(this._min)
const max = inverseMapping(this._max)
let percent = (value - min) / (max - min)
percent = Math.max(0, Math.min(percent, 1))

this.$fill.style.width = percent * 100 + '%'
}

return this
}

_initSlider() {
this._hasSlider = true

// Build DOM
// ---------------------------------------------------------------------

this.$slider = document.createElement('div')
this.$slider.classList.add('slider')

this.$fill = document.createElement('div')
this.$fill.classList.add('fill')

this.$slider.appendChild(this.$fill)
this.$widget.insertBefore(this.$slider, this.$input)

this.domElement.classList.add('hasSlider')

// Map clientX to value
// ---------------------------------------------------------------------

const min = inverseMapping(this._min)
const max = inverseMapping(this._max)

const clamp = (value) => {
if (value < min) value = min
if (value > max) value = max
return value
}

const map = (v, a, b, c, d) => {
return ((v - a) / (b - a)) * (d - c) + c
}

const setValueFromX = (clientX) => {
const rect = this.$slider.getBoundingClientRect()
let value = map(clientX, rect.left, rect.right, min, max)
this.setValue(mapping(clamp(this._snap(value))))
}

const mouseDown = (e) => {
this._setDraggingStyle(true)
setValueFromX(e.clientX)
window.addEventListener('pointermove', mouseMove)
window.addEventListener('pointerup', mouseUp)
}

const mouseMove = (e) => {
setValueFromX(e.clientX)
}

const mouseUp = () => {
this._callOnFinishChange()
this._setDraggingStyle(false)
window.removeEventListener('pointermove', mouseMove)
window.removeEventListener('pointerup', mouseUp)
}

this.$slider.addEventListener('pointerdown', mouseDown)
}
}
113 changes: 89 additions & 24 deletions src/utils/WebGLApp.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import {
Color,
HalfFloatType,
OrthographicCamera,
PerspectiveCamera,
Scene,
sRGBEncoding,
Vector3,
WebGLRenderer,
} from 'three'
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
import Stats from 'stats.js'
import { getGPUTier } from 'detect-gpu'
import { EffectComposer, RenderPass } from 'postprocessing'
import CannonDebugger from 'cannon-es-debugger'
import loadMP4Module, { isWebCodecsSupported } from 'mp4-wasm'
import { initControls } from './Controls'
import GUI from 'lil-gui'
import { ExponentialNumberController } from '../utils/ExponentialNumberController'

export default class WebGLApp {
#width
@@ -26,7 +36,7 @@ export default class WebGLApp {
#frames = []

get background() {
return this.renderer.getClearColor(new THREE.Color())
return this.renderer.getClearColor(new Color())
}

get backgroundAlpha() {
@@ -52,29 +62,26 @@ export default class WebGLApp {
frustumSize = 3,
near = 0.01,
far = 100,
gamma = true,
physicallyCorrectLights = true,
...options
} = {}) {
this.renderer = new THREE.WebGLRenderer({
this.renderer = new WebGLRenderer({
antialias: !options.postprocessing,
alpha: backgroundAlpha !== 1,
// enabled for recording gifs or videos,
// might disable it for performance reasons
preserveDrawingBuffer: true,
...options,
})
// enable gamma correction, read more about it here:
// https://www.donmccurdy.com/2020/06/17/color-management-in-threejs/
this.renderer.outputEncoding = sRGBEncoding
// this will be the default in the future
// https://github.com/mrdoob/three.js/issues/23614
this.renderer.physicallyCorrectLights = true

if (options.sortObjects !== undefined) {
this.renderer.sortObjects = options.sortObjects
}
if (gamma) {
// enable gamma correction, read more about it here:
// https://www.donmccurdy.com/2020/06/17/color-management-in-threejs/
this.renderer.outputEncoding = THREE.sRGBEncoding
}
if (physicallyCorrectLights) {
this.renderer.physicallyCorrectLights = true
}
if (options.xr) {
this.renderer.xr.enabled = true
}
@@ -95,9 +102,9 @@ export default class WebGLApp {
// setup the camera
const aspect = this.#width / this.#height
if (!options.orthographic) {
this.camera = new THREE.PerspectiveCamera(fov, aspect, near, far)
this.camera = new PerspectiveCamera(fov, aspect, near, far)
} else {
this.camera = new THREE.OrthographicCamera(
this.camera = new OrthographicCamera(
-(frustumSize * aspect) / 2,
(frustumSize * aspect) / 2,
frustumSize / 2,
@@ -107,10 +114,10 @@ export default class WebGLApp {
)
this.camera.frustumSize = frustumSize
}
this.camera.position.copy(options.cameraPosition || new THREE.Vector3(0, 0, 4))
this.camera.lookAt(0, 0, 0)
this.camera.position.copy(options.cameraPosition || new Vector3(0, 0, 4))
this.camera.lookAt(options.cameraTarget || new Vector3())

this.scene = new THREE.Scene()
this.scene = new Scene()

this.gl = this.renderer.getContext()

@@ -187,7 +194,7 @@ export default class WebGLApp {
const maxMultisampling = this.gl.getParameter(this.gl.MAX_SAMPLES)
this.composer = new EffectComposer(this.renderer, {
multisampling: Math.min(8, maxMultisampling),
frameBufferType: gamma ? THREE.HalfFloatType : undefined,
frameBufferType: HalfFloatType,
...options,
})
this.composer.addPass(new RenderPass(this.scene, this.camera))
@@ -223,9 +230,67 @@ export default class WebGLApp {
document.body.appendChild(this.stats.dom)
}

// initialize the controls-state
if (options.controls) {
this.controls = initControls(options.controls, options)
// initialize the gui
if (options.gui) {
this.gui = new GUI()

if (options.guiClosed) {
this.gui.close()
}

Object.assign(Object.getPrototypeOf(this.gui), {
// let's try to be smart
addSmart(object, key, name = '') {
const value = object[key]
switch (typeof value) {
case 'number': {
if (value === 0) {
return this.add(object, key, -10, 10, 0.01)
} else if (
0 < value &&
value < 1 &&
!['f', 'a', 'frequency', 'amplitude'].includes(name)
) {
return this.add(object, key, 0, 1, 0.01)
} else if (value > 0) {
return new ExponentialNumberController(
this,
object,
key,
0.01,
value < 100 ? 100 : 1000,
0.01
)
} else {
return this.add(object, key, -10, 0, 0.01)
}
}
case 'object': {
return this.addColor(object, key)
}
default: {
return this.add(object, key)
}
}
},
// specifically for three.js exposed uniforms
wireUniforms(folderName, uniforms, { blacklist = [] } = {}) {
const folder = this.addFolder(folderName)

Object.keys(uniforms).forEach((key) => {
if (blacklist.includes(key)) return
const uniformObject = uniforms[key]
folder.addSmart(uniformObject, 'value', key).name(key)
})
},
})

if (typeof options.gui === 'object') {
this.guiState = options.gui
Object.keys(options.gui).forEach((key) => {
this.gui.addSmart(this.guiState, key)
})
}
}

// detect the gpu info
39 changes: 23 additions & 16 deletions src/utils/loadEnvMap.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import * as THREE from 'three'
import {
CubeTextureLoader,
EquirectangularReflectionMapping,
PMREMGenerator,
sRGBEncoding,
TextureLoader,
UnsignedByteType,
} from 'three'
// TODO lazy load these, or put them in different files
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader.js'
import { EXRLoader } from 'three/examples/jsm/loaders/EXRLoader.js'
import { HDRCubeTextureLoader } from 'three/examples/jsm/loaders/HDRCubeTextureLoader.js'
import { RGBELoader } from 'three/addons/loaders/RGBELoader.js'
import { EXRLoader } from 'three/addons/loaders/EXRLoader.js'
import { HDRCubeTextureLoader } from 'three/addons/loaders/HDRCubeTextureLoader.js'

export default function loadEnvMap(url, { renderer, ...options }) {
if (!renderer) {
@@ -17,18 +24,18 @@ export default function loadEnvMap(url, { renderer, ...options }) {

switch (extension) {
case 'hdr': {
loader = new RGBELoader().setDataType(THREE.UnsignedByteType).loadAsync(url)
loader = new RGBELoader().setDataType(UnsignedByteType).loadAsync(url)
break
}
case 'exr': {
loader = new EXRLoader().setDataType(THREE.UnsignedByteType).loadAsync(url)
loader = new EXRLoader().setDataType(UnsignedByteType).loadAsync(url)
break
}
case 'png':
case 'jpg': {
loader = new THREE.TextureLoader().loadAsync(url).then((texture) => {
if (renderer.outputEncoding === THREE.sRGBEncoding && !options.linear) {
texture.encoding = THREE.sRGBEncoding
loader = new TextureLoader().loadAsync(url).then((texture) => {
if (renderer.outputEncoding === sRGBEncoding && !options.linear) {
texture.encoding = sRGBEncoding
}
return texture
})
@@ -51,14 +58,14 @@ export default function loadEnvMap(url, { renderer, ...options }) {

switch (extension) {
case 'hdr': {
loader = new HDRCubeTextureLoader().setDataType(THREE.UnsignedByteType).loadAsync(url)
loader = new HDRCubeTextureLoader().setDataType(UnsignedByteType).loadAsync(url)
break
}
case 'png':
case 'jpg': {
loader = new THREE.CubeTextureLoader().loadAsync(url).then((texture) => {
if (renderer.outputEncoding === THREE.sRGBEncoding && !options.linear) {
texture.encoding = THREE.sRGBEncoding
loader = new CubeTextureLoader().loadAsync(url).then((texture) => {
if (renderer.outputEncoding === sRGBEncoding && !options.linear) {
texture.encoding = sRGBEncoding
}
return texture
})
@@ -94,7 +101,7 @@ export default function loadEnvMap(url, { renderer, ...options }) {

// prefilter the equirectangular environment map for irradiance
function equirectangularToPMREMCube(texture, renderer) {
const pmremGenerator = new THREE.PMREMGenerator(renderer)
const pmremGenerator = new PMREMGenerator(renderer)
pmremGenerator.compileEquirectangularShader()

const cubeRenderTarget = pmremGenerator.fromEquirectangular(texture)
@@ -108,7 +115,7 @@ function equirectangularToPMREMCube(texture, renderer) {

// prefilter the cubemap environment map for irradiance
function cubeToPMREMCube(texture, renderer) {
const pmremGenerator = new THREE.PMREMGenerator(renderer)
const pmremGenerator = new PMREMGenerator(renderer)
pmremGenerator.compileCubemapShader()

const cubeRenderTarget = pmremGenerator.fromCubemap(texture)
@@ -123,6 +130,6 @@ function cubeToPMREMCube(texture, renderer) {
// transform an equirectangular texture to a cubetexture that
// can be used as an envmap or scene background
function equirectangularToCube(texture) {
texture.mapping = THREE.EquirectangularReflectionMapping
texture.mapping = EquirectangularReflectionMapping
return texture
}
4 changes: 2 additions & 2 deletions src/utils/loadGLTF.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js'
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js'

export default function loadGLTF(url, options = {}) {
return new Promise((resolve, reject) => {
8 changes: 4 additions & 4 deletions src/utils/loadTexture.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import * as THREE from 'three'
import { sRGBEncoding, TextureLoader } from 'three'

export default function loadTexture(url, { renderer, ...options }) {
if (!renderer) {
throw new Error(`Texture requires renderer to passed in the options for ${url}!`)
}

return new Promise((resolve, reject) => {
new THREE.TextureLoader().load(
new TextureLoader().load(
url,
(texture) => {
// apply eventual gamma encoding
if (renderer.outputEncoding === THREE.sRGBEncoding && !options.linear) {
texture.encoding = THREE.sRGBEncoding
if (renderer.outputEncoding === sRGBEncoding && !options.linear) {
texture.encoding = sRGBEncoding
}

// apply eventual texture options, such as wrap, repeat...
134 changes: 5 additions & 129 deletions yarn.lock
Original file line number Diff line number Diff line change
@@ -818,24 +818,6 @@ connect@3.6.6:
parseurl "~1.3.2"
utils-merge "1.0.1"

controls-gui@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/controls-gui/-/controls-gui-2.0.0.tgz#8f6ad1f0435ffeba931f7398597f496c0f7c7ff6"
integrity sha512-biqTR+5fqXnQvXiQ54fA7Ta85O31eG7RxMxSCpwD0/yhAm7ipGNqv9+NLM48BTWsyJXsgC5PDR3wHbKN1i793g==
dependencies:
defaults "^1.0.3"
insert-css "^2.0.0"
preact "^8.4.2"

controls-state@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/controls-state/-/controls-state-2.0.0.tgz#b7e18625e4f8d7ab1c51143ae6c03b09303b5958"
integrity sha512-9tXQ4fgmXQCLgYlEQ58G+xab97vCnIL2+tlzbEBrErxzt2GipdaRXTQZfD2b3M8VS5fY0aF5mGSM950Q9HcYPw==
dependencies:
event-emitter "^0.3.5"
global "^4.3.2"
raf "^3.4.1"

cookie@~0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1"
@@ -884,14 +866,6 @@ cross-spawn@^7.0.2, cross-spawn@^7.0.3:
shebang-command "^2.0.0"
which "^2.0.1"

d@1, d@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a"
integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==
dependencies:
es5-ext "^0.10.50"
type "^1.0.1"

debug@2.6.9, debug@^2.2.0, debug@^2.6.0:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
@@ -989,11 +963,6 @@ doctrine@^3.0.0:
dependencies:
esutils "^2.0.2"

dom-walk@^0.1.0:
version "0.1.2"
resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84"
integrity sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==

duplexer2@~0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1"
@@ -1102,32 +1071,6 @@ error-ex@^1.3.1:
dependencies:
is-arrayish "^0.2.1"

es5-ext@^0.10.35, es5-ext@^0.10.50, es5-ext@~0.10.14:
version "0.10.53"
resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.53.tgz#93c5a3acfdbef275220ad72644ad02ee18368de1"
integrity sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==
dependencies:
es6-iterator "~2.0.3"
es6-symbol "~3.1.3"
next-tick "~1.0.0"

es6-iterator@~2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7"
integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c=
dependencies:
d "1"
es5-ext "^0.10.35"
es6-symbol "^3.1.1"

es6-symbol@^3.1.1, es6-symbol@~3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18"
integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==
dependencies:
d "^1.0.1"
ext "^1.1.2"

esbuild-plugin-glslify-inline@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/esbuild-plugin-glslify-inline/-/esbuild-plugin-glslify-inline-1.1.0.tgz#a0d7279ee8dc730b08ccb3ae6ab3a71fb120c1f5"
@@ -1330,14 +1273,6 @@ etag@1.8.1, etag@^1.8.1, etag@~1.8.1:
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=

event-emitter@^0.3.5:
version "0.3.5"
resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39"
integrity sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=
dependencies:
d "1"
es5-ext "~0.10.14"

eventemitter3@^4.0.0:
version "4.0.7"
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
@@ -1348,13 +1283,6 @@ events@^3.2.0:
resolved "https://registry.yarnpkg.com/events/-/events-3.2.0.tgz#93b87c18f8efcd4202a461aec4dfc0556b639379"
integrity sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==

ext@^1.1.2:
version "1.4.0"
resolved "https://registry.yarnpkg.com/ext/-/ext-1.4.0.tgz#89ae7a07158f79d35517882904324077e4379244"
integrity sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==
dependencies:
type "^2.0.0"

falafel@^2.1.0:
version "2.2.4"
resolved "https://registry.yarnpkg.com/falafel/-/falafel-2.2.4.tgz#b5d86c060c2412a43166243cb1bce44d1abd2819"
@@ -1638,14 +1566,6 @@ global-prefix@^3.0.0:
kind-of "^6.0.2"
which "^1.3.1"

global@^4.3.2:
version "4.4.0"
resolved "https://registry.yarnpkg.com/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406"
integrity sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==
dependencies:
min-document "^2.19.0"
process "^0.11.10"

globals@^13.19.0:
version "13.19.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-13.19.0.tgz#7a42de8e6ad4f7242fbcca27ea5b23aca367b5c8"
@@ -1961,11 +1881,6 @@ ini@^1.3.5:
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==

insert-css@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/insert-css/-/insert-css-2.0.0.tgz#eb5d1097b7542f4c79ea3060d3aee07d053880f4"
integrity sha1-610Ql7dUL0x56jBg067gfQU4gPQ=

is-arrayish@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
@@ -2152,6 +2067,11 @@ levn@~0.3.0:
prelude-ls "~1.1.2"
type-check "~0.3.2"

lil-gui@^0.17.0:
version "0.17.0"
resolved "https://registry.yarnpkg.com/lil-gui/-/lil-gui-0.17.0.tgz#b41ae55d0023fcd9185f7395a218db0f58189663"
integrity sha512-MVBHmgY+uEbmJNApAaPbtvNh1RCAeMnKym82SBjtp5rODTYKWtM+MXHCifLe2H2Ti1HuBGBtK/5SyG4ShQ3pUQ==

limiter@^1.0.5:
version "1.1.5"
resolved "https://registry.yarnpkg.com/limiter/-/limiter-1.1.5.tgz#8f92a25b3b16c6131293a0cc834b4a838a2aa7c2"
@@ -2289,13 +2209,6 @@ mimic-fn@^2.1.0:
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==

min-document@^2.19.0:
version "2.19.0"
resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685"
integrity sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=
dependencies:
dom-walk "^0.1.0"

minimatch@^3.0.2, minimatch@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
@@ -2368,11 +2281,6 @@ negotiator@0.6.2:
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==

next-tick@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c"
integrity sha1-yobR/ogoFpsBICCOPchCS524NCw=

node-releases@^2.0.6:
version "2.0.8"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.8.tgz#0f349cdc8fcfa39a92ac0be9bc48b7706292b9ae"
@@ -2593,11 +2501,6 @@ path-type@^4.0.0:
resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==

performance-now@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=

picocolors@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
@@ -2633,11 +2536,6 @@ postprocessing@^6.29.1:
resolved "https://registry.yarnpkg.com/postprocessing/-/postprocessing-6.29.1.tgz#169b48cca498a52d3ee4b8960645b089cc7f64b3"
integrity sha512-w+XoL2Z7YpVDsHbIeg6sldMMmDqZS4Hul1FDq3TjOeXZ0Wnp0Qy1EvR7QmYJxyWBux1cKQx/k3XO7LxfvPsZyg==

preact@^8.4.2:
version "8.5.3"
resolved "https://registry.yarnpkg.com/preact/-/preact-8.5.3.tgz#78c2a5562fcecb1fed1d0055fa4ac1e27bde17c1"
integrity sha512-O3kKP+1YdgqHOFsZF2a9JVdtqD+RPzCQc3rP+Ualf7V6rmRDchZ9MJbiGTT7LuyqFKZqlHSOyO/oMFmI2lVTsw==

prelude-ls@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
@@ -2665,11 +2563,6 @@ process-nextick-args@~2.0.0:
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==

process@^0.11.10:
version "0.11.10"
resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI=

prompts@^2.4.2:
version "2.4.2"
resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069"
@@ -2690,13 +2583,6 @@ qs@^6.11.0:
dependencies:
side-channel "^1.0.4"

raf@^3.4.1:
version "3.4.1"
resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39"
integrity sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==
dependencies:
performance-now "^2.1.0"

range-parser@~1.2.0:
version "1.2.1"
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
@@ -3304,16 +3190,6 @@ type-fest@^0.20.2:
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==

type@^1.0.1:
version "1.2.0"
resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0"
integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==

type@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/type/-/type-2.1.0.tgz#9bdc22c648cf8cf86dd23d32336a41cfb6475e3f"
integrity sha512-G9absDWvhAWCV2gmF1zKud3OyC61nZDwWvBL2DApaVFogI07CprggiQAOOjvp2NRjYWFzPyu7vwtDrQFq8jeSA==

typedarray@^0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"

0 comments on commit 2db23b1

Please sign in to comment.