-
-
Notifications
You must be signed in to change notification settings - Fork 36k
Sky: Add WebGPURenderer
version.
#29013
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 1 commit
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
import { | ||
BackSide, | ||
BoxGeometry, | ||
Mesh, | ||
NodeMaterial, | ||
Vector3 | ||
} from 'three'; | ||
import { float, tslFn, vec3, acos, add, mul, clamp, cos, dot, exp, max, mix, modelViewProjection, normalize, positionWorld, pow, smoothstep, sub, varying, varyingProperty, vec4, uniform } from 'three/tsl'; | ||
|
||
/** | ||
* Based on "A Practical Analytic Model for Daylight" | ||
* aka The Preetham Model, the de facto standard analytic skydome model | ||
* https://www.researchgate.net/publication/220720443_A_Practical_Analytic_Model_for_Daylight | ||
* | ||
* First implemented by Simon Wallner | ||
* http://simonwallner.at/project/atmospheric-scattering/ | ||
* | ||
* Improved by Martin Upitis | ||
* http://blenderartists.org/forum/showthread.php?245954-preethams-sky-impementation-HDR | ||
* | ||
* Three.js integration by zz85 http://twitter.com/blurspline | ||
*/ | ||
|
||
class Sky extends Mesh { | ||
|
||
constructor() { | ||
|
||
const material = new NodeMaterial(); | ||
|
||
super( new BoxGeometry( 1, 1, 1 ), material ); | ||
|
||
this.turbidity = uniform( 2 ); | ||
this.rayleigh = uniform( 1 ); | ||
this.mieCoefficient = uniform( 0.005 ); | ||
this.mieDirectionalG = uniform( 0.8 ); | ||
this.sunPosition = uniform( new Vector3() ); | ||
this.up = uniform( new Vector3( 0, 1, 0 ) ); | ||
this.cameraPosition = uniform( new Vector3() ).label( 'cameraPosition' ).onRenderUpdate( ( { camera }, self ) => self.value.setFromMatrixPosition( camera.matrixWorld ) ); // TODO replace with cameraPosition from CameraNode | ||
sunag marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
this.isSky = true; | ||
|
||
const vertexNode = /*@__PURE__*/ tslFn( () => { | ||
|
||
// constants for atmospheric scattering | ||
const e = float( 2.71828182845904523536028747135266249775724709369995957 ); | ||
// const pi = float( 3.141592653589793238462643383279502884197169 ); | ||
|
||
// wavelength of used primaries, according to preetham | ||
// const lambda = vec3( 680E-9, 550E-9, 450E-9 ); | ||
// this pre-calcuation replaces older TotalRayleigh(vec3 lambda) function: | ||
// (8.0 * pow(pi, 3.0) * pow(pow(n, 2.0) - 1.0, 2.0) * (6.0 + 3.0 * pn)) / (3.0 * N * pow(lambda, vec3(4.0)) * (6.0 - 7.0 * pn)) | ||
const totalRayleigh = vec3( 5.804542996261093E-6, 1.3562911419845635E-5, 3.0265902468824876E-5 ); | ||
|
||
// mie stuff | ||
// K coefficient for the primaries | ||
// const v = float( 4.0 ); | ||
// const K = vec3( 0.686, 0.678, 0.666 ); | ||
// MieConst = pi * pow( ( 2.0 * pi ) / lambda, vec3( v - 2.0 ) ) * K | ||
const MieConst = vec3( 1.8399918514433978E14, 2.7798023919660528E14, 4.0790479543861094E14 ); | ||
|
||
// earth shadow hack | ||
// cutoffAngle = pi / 1.95; | ||
const cutoffAngle = float( 1.6110731556870734 ); | ||
const steepness = float( 1.5 ); | ||
const EE = float( 1000.0 ); | ||
|
||
// varying sun position | ||
|
||
const vSunDirection = normalize( this.sunPosition ); | ||
varyingProperty( 'vec3', 'vSunDirection' ).assign( vSunDirection ); | ||
|
||
// varying sun intensity | ||
|
||
const angle = dot( vSunDirection, this.up ); | ||
const zenithAngleCos = clamp( angle, - 1, 1 ); | ||
const sunIntensity = EE.mul( max( 0.0, float( 1.0 ).sub( pow( e, cutoffAngle.sub( acos( zenithAngleCos ) ).div( steepness ).negate() ) ) ) ); | ||
varyingProperty( 'float', 'vSunE' ).assign( sunIntensity ); | ||
|
||
// varying sun fade | ||
|
||
const vSunfade = float( 1.0 ).sub( clamp( float( 1.0 ).sub( exp( this.sunPosition.y.div( 450000.0 ) ) ), 0, 1 ) ); | ||
varyingProperty( 'float', 'vSunfade' ).assign( vSunfade ); | ||
|
||
// varying vBetaR | ||
|
||
const rayleighCoefficient = this.rayleigh.sub( float( 1.0 ).mul( float( 1.0 ).sub( vSunfade ) ) ); | ||
|
||
// extinction (absorbtion + out scattering) | ||
// rayleigh coefficients | ||
varyingProperty( 'vec3', 'vBetaR' ).assign( totalRayleigh.mul( rayleighCoefficient ) ); | ||
|
||
// varying vBetaM | ||
|
||
const c = float( 0.2 ).mul( this.turbidity ).mul( 10E-18 ); | ||
const totalMie = float( 0.434 ).mul( c ).mul( MieConst ); | ||
|
||
varyingProperty( 'vec3', 'vBetaM' ).assign( totalMie.mul( this.mieCoefficient ) ); | ||
|
||
// position | ||
|
||
const position = modelViewProjection(); | ||
position.z.assign( position.w ); // set z to camera.far | ||
|
||
return position; | ||
|
||
} )(); | ||
|
||
const fragmentNode = /*@__PURE__*/ tslFn( () => { | ||
|
||
const vSunDirection = varying( vec3(), 'vSunDirection' ); | ||
const vSunE = varying( float(), 'vSunE' ); | ||
const vSunfade = varying( float(), 'vSunfade' ); | ||
const vBetaR = varying( vec3(), 'vBetaR' ); | ||
const vBetaM = varying( vec3(), 'vBetaM' ); | ||
|
||
// constants for atmospheric scattering | ||
const pi = float( 3.141592653589793238462643383279502884197169 ); | ||
|
||
// optical length at zenith for molecules | ||
const rayleighZenithLength = float( 8.4E3 ); | ||
const mieZenithLength = float( 1.25E3 ); | ||
// 66 arc seconds -> degrees, and the cosine of that | ||
const sunAngularDiameterCos = float( 0.999956676946448443553574619906976478926848692873900859324 ); | ||
|
||
// 3.0 / ( 16.0 * pi ) | ||
const THREE_OVER_SIXTEENPI = float( 0.05968310365946075 ); | ||
// 1.0 / ( 4.0 * pi ) | ||
const ONE_OVER_FOURPI = float( 0.07957747154594767 ); | ||
|
||
// | ||
|
||
const direction = normalize( positionWorld.sub( this.cameraPosition ) ); | ||
|
||
// optical length | ||
// cutoff angle at 90 to avoid singularity in next formula. | ||
const zenithAngle = acos( max( 0.0, dot( this.up, direction ) ) ); | ||
const inverse = float( 1.0 ).div( cos( zenithAngle ).add( float( 0.15 ).mul( pow( float( 93.885 ).sub( zenithAngle.mul( 180.0 ).div( pi ) ), - 1.253 ) ) ) ); | ||
const sR = rayleighZenithLength.mul( inverse ); | ||
const sM = mieZenithLength.mul( inverse ); | ||
|
||
// combined extinction factor | ||
const Fex = exp( mul( vBetaR, sR ).add( mul( vBetaM, sM ) ).negate() ); | ||
|
||
// in scattering | ||
const cosTheta = dot( direction, vSunDirection ); | ||
|
||
// betaRTheta | ||
|
||
const c = cosTheta.mul( 0.5 ).add( 0.5 ); | ||
const rPhase = THREE_OVER_SIXTEENPI.mul( float( 1.0 ).add( pow( c, 2.0 ) ) ); | ||
const betaRTheta = vBetaR.mul( rPhase ); | ||
|
||
// betaMTheta | ||
|
||
const g2 = pow( this.mieDirectionalG, 2.0 ); | ||
const inv = float( 1.0 ).div( pow( float( 1.0 ).sub( float( 2.0 ).mul( this.mieDirectionalG ).mul( cosTheta ) ).add( g2 ), 1.5 ) ); | ||
const mPhase = ONE_OVER_FOURPI.mul( float( 1.0 ).sub( g2 ) ).mul( inv ); | ||
const betaMTheta = vBetaM.mul( mPhase ); | ||
|
||
const Lin = pow( vSunE.mul( add( betaRTheta, betaMTheta ).div( add( vBetaR, vBetaM ) ) ).mul( sub( 1.0, Fex ) ), vec3( 1.5 ) ); | ||
Lin.mulAssign( mix( vec3( 1.0 ), pow( vSunE.mul( add( betaRTheta, betaMTheta ).div( add( vBetaR, vBetaM ) ) ).mul( Fex ), vec3( 1.0 / 2.0 ) ), clamp( pow( sub( 1.0, dot( this.up, vSunDirection ) ), 5.0 ), 0.0, 1.0 ) ) ); | ||
|
||
// nightsky | ||
|
||
const L0 = vec3( 0.1 ).mul( Fex ); | ||
|
||
// composition + solar disc | ||
const sundisk = smoothstep( sunAngularDiameterCos, sunAngularDiameterCos.add( 0.00002 ), cosTheta ); | ||
L0.addAssign( vSunE.mul( 19000.0 ).mul( Fex ).mul( sundisk ) ); | ||
|
||
const texColor = add( Lin, L0 ).mul( 0.04 ).add( vec3( 0.0, 0.0003, 0.00075 ) ); | ||
|
||
const retColor = pow( texColor, vec3( float( 1.0 ).div( float( 1.2 ).add( vSunfade.mul( 1.2 ) ) ) ) ); | ||
|
||
return vec4( retColor, 1.0 ); | ||
|
||
} )(); | ||
|
||
material.normals = false; | ||
material.side = BackSide; | ||
material.depthWrite = false; | ||
|
||
material.vertexNode = vertexNode; | ||
material.fragmentNode = fragmentNode; | ||
|
||
} | ||
|
||
} | ||
|
||
export { Sky }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<title>three.js webgpu - sky</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="https://threejs.org" target="_blank" rel="noopener">three.js</a> webgpu - sky + sun shader | ||
</div> | ||
|
||
<script type="importmap"> | ||
{ | ||
"imports": { | ||
"three": "../build/three.webgpu.js", | ||
"three/tsl": "../build/three.webgpu.js", | ||
"three/addons/": "./jsm/" | ||
} | ||
} | ||
</script> | ||
|
||
<script type="module"> | ||
|
||
import * as THREE from 'three'; | ||
|
||
import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; | ||
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; | ||
import { Sky } from 'three/addons/objects/SkyGPU.js'; | ||
|
||
let camera, scene, renderer; | ||
|
||
let sky, sun; | ||
|
||
init(); | ||
|
||
function initSky() { | ||
|
||
// Add Sky | ||
sky = new Sky(); | ||
sky.scale.setScalar( 450000 ); | ||
scene.add( sky ); | ||
|
||
sun = new THREE.Vector3(); | ||
|
||
/// GUI | ||
|
||
const effectController = { | ||
turbidity: 10, | ||
rayleigh: 3, | ||
mieCoefficient: 0.005, | ||
mieDirectionalG: 0.7, | ||
elevation: 2, | ||
azimuth: 180, | ||
exposure: renderer.toneMappingExposure | ||
}; | ||
|
||
function guiChanged() { | ||
|
||
sky.turbidity.value = effectController.turbidity; | ||
sky.rayleigh.value = effectController.rayleigh; | ||
sky.mieCoefficient.value = effectController.mieCoefficient; | ||
sky.mieDirectionalG.value = effectController.mieDirectionalG; | ||
|
||
const phi = THREE.MathUtils.degToRad( 90 - effectController.elevation ); | ||
const theta = THREE.MathUtils.degToRad( effectController.azimuth ); | ||
|
||
sun.setFromSphericalCoords( 1, phi, theta ); | ||
|
||
sky.sunPosition.value.copy( sun ); | ||
|
||
renderer.toneMappingExposure = effectController.exposure; | ||
|
||
} | ||
|
||
const gui = new GUI(); | ||
|
||
gui.add( effectController, 'turbidity', 0.0, 20.0, 0.1 ).onChange( guiChanged ); | ||
gui.add( effectController, 'rayleigh', 0.0, 4, 0.001 ).onChange( guiChanged ); | ||
gui.add( effectController, 'mieCoefficient', 0.0, 0.1, 0.001 ).onChange( guiChanged ); | ||
gui.add( effectController, 'mieDirectionalG', 0.0, 1, 0.001 ).onChange( guiChanged ); | ||
gui.add( effectController, 'elevation', 0, 90, 0.1 ).onChange( guiChanged ); | ||
gui.add( effectController, 'azimuth', - 180, 180, 0.1 ).onChange( guiChanged ); | ||
gui.add( effectController, 'exposure', 0, 1, 0.0001 ).onChange( guiChanged ); | ||
|
||
guiChanged(); | ||
|
||
} | ||
|
||
function init() { | ||
|
||
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 100, 2000000 ); | ||
camera.position.set( 0, 100, 2000 ); | ||
|
||
scene = new THREE.Scene(); | ||
|
||
renderer = new THREE.WebGPURenderer(); | ||
renderer.setPixelRatio( window.devicePixelRatio ); | ||
renderer.setSize( window.innerWidth, window.innerHeight ); | ||
renderer.setAnimationLoop( animate ); | ||
renderer.toneMapping = THREE.ACESFilmicToneMapping; | ||
renderer.toneMappingExposure = 0.5; | ||
document.body.appendChild( renderer.domElement ); | ||
|
||
const controls = new OrbitControls( camera, renderer.domElement ); | ||
//controls.maxPolarAngle = Math.PI / 2; | ||
controls.enableZoom = false; | ||
controls.enablePan = false; | ||
|
||
initSky(); | ||
|
||
window.addEventListener( 'resize', onWindowResize ); | ||
|
||
} | ||
|
||
function onWindowResize() { | ||
|
||
camera.aspect = window.innerWidth / window.innerHeight; | ||
camera.updateProjectionMatrix(); | ||
|
||
renderer.setSize( window.innerWidth, window.innerHeight ); | ||
|
||
} | ||
|
||
function animate() { | ||
|
||
renderer.render( scene, camera ); | ||
|
||
} | ||
|
||
</script> | ||
|
||
</body> | ||
|
||
</html> |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.