Skip to content
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

WebGPURenderer: PassNode + PostProcessing - WebGPUBackend #27537

Merged
merged 4 commits into from
Jan 17, 2024
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions examples/jsm/nodes/display/PassNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { NodeUpdateType } from '../core/constants.js';
import { nodeObject } from '../shadernode/ShaderNode.js';
import { uniform } from '../core/UniformNode.js';
import { viewZToOrthographicDepth, perspectiveDepthToViewZ } from './ViewportDepthNode.js';
import { RenderTarget, Vector2, HalfFloatType, DepthTexture, FloatType, NoToneMapping } from 'three';
import { RenderTarget, Vector2, HalfFloatType, DepthTexture, NoToneMapping/*, FloatType*/ } from 'three';

class PassTextureNode extends TextureNode {

Expand Down Expand Up @@ -51,7 +51,7 @@ class PassNode extends TempNode {

const depthTexture = new DepthTexture();
depthTexture.isRenderTargetTexture = true;
depthTexture.type = FloatType;
//depthTexture.type = FloatType;
depthTexture.name = 'PostProcessingDepth';

const renderTarget = new RenderTarget( this._width * this._pixelRatio, this._height * this._pixelRatio, { type: HalfFloatType } );
Expand Down
5 changes: 1 addition & 4 deletions examples/jsm/nodes/display/ViewportDepthTextureNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import ViewportTextureNode from './ViewportTextureNode.js';
import { addNodeClass } from '../core/Node.js';
import { addNodeElement, nodeProxy } from '../shadernode/ShaderNode.js';
import { viewportTopLeft } from './ViewportNode.js';
import { DepthTexture, NearestMipmapNearestFilter, DepthFormat, UnsignedIntType } from 'three';
import { DepthTexture } from 'three';

let sharedDepthbuffer = null;

Expand All @@ -13,9 +13,6 @@ class ViewportDepthTextureNode extends ViewportTextureNode {
if ( sharedDepthbuffer === null ) {

sharedDepthbuffer = new DepthTexture();
sharedDepthbuffer.minFilter = NearestMipmapNearestFilter;
sharedDepthbuffer.type = UnsignedIntType;
sharedDepthbuffer.format = DepthFormat;

}

Expand Down
8 changes: 4 additions & 4 deletions examples/jsm/nodes/display/ViewportSharedTextureNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@ import { addNodeElement, nodeProxy } from '../shadernode/ShaderNode.js';
import { viewportTopLeft } from './ViewportNode.js';
import { FramebufferTexture } from 'three';

let sharedFramebuffer = null;
let _sharedFramebuffer = null;

class ViewportSharedTextureNode extends ViewportTextureNode {

constructor( uvNode = viewportTopLeft, levelNode = null ) {

if ( sharedFramebuffer === null ) {
if ( _sharedFramebuffer === null ) {

sharedFramebuffer = new FramebufferTexture();
_sharedFramebuffer = new FramebufferTexture();

}

super( uvNode, levelNode, sharedFramebuffer );
super( uvNode, levelNode, _sharedFramebuffer );

}

Expand Down
21 changes: 20 additions & 1 deletion examples/jsm/renderers/common/Textures.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import DataMap from './DataMap.js';

import { Vector3, DepthTexture, DepthStencilFormat, DepthFormat, UnsignedIntType, UnsignedInt248Type, LinearFilter, NearestFilter, EquirectangularReflectionMapping, EquirectangularRefractionMapping, CubeReflectionMapping, CubeRefractionMapping } from 'three';
import { Vector3, DepthTexture, DepthStencilFormat, DepthFormat, UnsignedIntType, UnsignedInt248Type, LinearFilter, NearestFilter, EquirectangularReflectionMapping, EquirectangularRefractionMapping, CubeReflectionMapping, CubeRefractionMapping, UnsignedByteType } from 'three';

const _size = new Vector3();

Expand Down Expand Up @@ -153,6 +153,25 @@ class Textures extends DataMap {

//

if ( texture.isFramebufferTexture ) {

const renderer = this.backend.renderer;
const renderTarget = renderer.getRenderTarget();

if ( renderTarget ) {

texture.type = renderTarget.texture.type;

} else {

texture.type = UnsignedByteType;

}

}

//

const { width, height, depth } = this.getSize( texture );

options.width = width;
Expand Down
32 changes: 28 additions & 4 deletions examples/jsm/renderers/webgpu/WebGPUBackend.js
Original file line number Diff line number Diff line change
Expand Up @@ -1173,18 +1173,42 @@ class WebGPUBackend extends Backend {

let sourceGPU = null;

if ( texture.isFramebufferTexture ) {
if ( renderContext.renderTarget ) {

sourceGPU = this.context.getCurrentTexture();
if ( texture.isDepthTexture ) {

} else if ( texture.isDepthTexture ) {
sourceGPU = this.get( renderContext.depthTexture ).texture;

sourceGPU = this.textureUtils.getDepthBuffer( renderContext.depth, renderContext.stencil );
} else {

sourceGPU = this.get( renderContext.textures[ 0 ] ).texture;

}

} else {

if ( texture.isDepthTexture ) {

sourceGPU = this.textureUtils.getDepthBuffer( renderContext.depth, renderContext.stencil );

} else {

sourceGPU = this.context.getCurrentTexture();

}

}

const destinationGPU = this.get( texture ).texture;

if ( sourceGPU.format !== destinationGPU.format ) {

console.error( 'WebGPUBackend: copyFramebufferToTexture: Source and destination formats do not match.', sourceGPU.format, destinationGPU.format );

return;

}

renderContextData.currentPass.end();

encoder.copyTextureToTexture(
Expand Down
2 changes: 1 addition & 1 deletion examples/jsm/renderers/webgpu/utils/WebGPUTextureUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -755,7 +755,7 @@ export function getFormat( texture, device = null ) {

let formatGPU;

if ( /*texture.isRenderTargetTexture === true ||*/ texture.isFramebufferTexture === true ) {
if ( texture.isFramebufferTexture === true && texture.type === UnsignedByteType ) {

formatGPU = GPUTextureFormat.BGRA8Unorm;

Expand Down
Binary file modified examples/screenshots/webgpu_backdrop_water.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
77 changes: 55 additions & 22 deletions examples/webgpu_backdrop_water.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,15 @@
<script type="module">

import * as THREE from 'three';
import { color, depth, depthTexture, normalWorld, triplanarTexture, texture, viewportSharedTexture, mx_worley_noise_float, positionWorld, timerLocal, MeshStandardNodeMaterial, MeshBasicNodeMaterial } from 'three/nodes';
import { color, depth, vec2, pass, depthTexture, normalWorld, triplanarTexture, texture, objectPosition, viewportTopLeft, viewportDepthTexture, viewportSharedTexture, mx_worley_noise_float, positionWorld, timerLocal, MeshStandardNodeMaterial, MeshBasicNodeMaterial } from 'three/nodes';

import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';

import WebGPU from 'three/addons/capabilities/WebGPU.js';
import WebGL from 'three/addons/capabilities/WebGL.js';

import WebGPURenderer from 'three/addons/renderers/webgpu/WebGPURenderer.js';
import PostProcessing from 'three/addons/renderers/common/PostProcessing.js';

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

Expand All @@ -43,6 +44,8 @@
let camera, scene, renderer;
let mixer, objects, clock;
let model, floor, floorPosition;
let postProcessing;
let controls;
let stats;

init();
Expand All @@ -58,25 +61,25 @@
}

camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 0.25, 30 );
camera.position.set( 3, 3, 4 );
camera.position.set( 3, 2, 4 );

scene = new THREE.Scene();
scene.fog = new THREE.Fog( 0x74ccf4, 7, 25 );
scene.backgroundNode = normalWorld.y.mix( color( 0x74ccf4 ), color( 0x0066ff ) );
scene.fog = new THREE.Fog( 0x0487e2, 7, 25 );
scene.backgroundNode = normalWorld.y.mix( color( 0x0487e2 ), color( 0x0066ff ) );
camera.lookAt( 0, 1, 0 );

const sunLight = new THREE.DirectionalLight( 0xFFE499, 5 );
sunLight.castShadow = true;
sunLight.shadow.camera.near = .1;
sunLight.shadow.camera.far = 3;
sunLight.shadow.camera.far = 5;
sunLight.shadow.camera.right = 2;
sunLight.shadow.camera.left = - 2;
sunLight.shadow.camera.top = 2;
sunLight.shadow.camera.top = 1;
sunLight.shadow.camera.bottom = - 2;
sunLight.shadow.mapSize.width = 2048;
sunLight.shadow.mapSize.height = 2048;
sunLight.shadow.bias = - 0.001;
sunLight.position.set( 1, 3, 1 );
sunLight.position.set( .5, 3, .5 );

const waterAmbientLight = new THREE.HemisphereLight( 0x333366, 0x74ccf4, 5 );
const skyAmbientLight = new THREE.HemisphereLight( 0x74ccf4, 0, 1 );
Expand Down Expand Up @@ -112,7 +115,7 @@
iceDiffuse.wrapT = THREE.RepeatWrapping;
iceDiffuse.colorSpace = THREE.NoColorSpace;

const iceColorNode = triplanarTexture( texture( iceDiffuse ) ).add( color( 0x0066ff ) );
const iceColorNode = triplanarTexture( texture( iceDiffuse ) ).add( color( 0x0066ff ) ).mul( .8 );

const geometry = new THREE.IcosahedronGeometry( 1, 3 );
const material = new MeshStandardNodeMaterial( { colorNode: iceColorNode } );
Expand All @@ -137,34 +140,44 @@

objects.position.set(
( ( column - 1 ) * scale ) * - .5,
- .3,
- 1,
( ( count / column ) * scale ) * - .5
);

scene.add( objects );

// water

const depthEffect = depthTexture().distance( depth ).remapClamp( 0, .05 );

const timer = timerLocal( .8 );
const floorUV = positionWorld.xzy;

const waterLayer0 = mx_worley_noise_float( floorUV.mul( 4 ).add( timer ) );
const waterLayer1 = mx_worley_noise_float( floorUV.mul( 2 ).add( timer ) );

const waterIntensity = waterLayer0.mul( waterLayer1 ).mul( 1.4 );
const waterColor = waterIntensity.mix( color( 0x0f5e9c ), color( 0x74ccf4 ) );
const viewportTexture = viewportSharedTexture();
const waterIntensity = waterLayer0.mul( waterLayer1 );
const waterColor = waterIntensity.mul( 1.4 ).mix( color( 0x0487e2 ), color( 0x74ccf4 ) );

const depthWater = depthTexture( viewportDepthTexture() ).sub( depth );
const depthEffect = depthWater.remapClamp( - .002, .04 );

const refractionUV = viewportTopLeft.add( vec2( 0, waterIntensity.mul( .1 ) ) );

const depthTestForRefraction = depthTexture( viewportDepthTexture( refractionUV ) ).sub( depth );

const depthRefraction = depthTestForRefraction.remapClamp( 0, .1 );

const finalUV = depthTestForRefraction.lessThan( 0 ).cond( viewportTopLeft, refractionUV );

const viewportTexture = viewportSharedTexture( finalUV );

const waterMaterial = new MeshBasicNodeMaterial();
waterMaterial.colorNode = waterColor;
waterMaterial.backdropNode = depthEffect.mul( 3 ).min( 1.4 ).mix( viewportTexture, viewportTexture.mul( color( 0x74ccf4 ) ) );
waterMaterial.backdropAlphaNode = depthEffect.oneMinus();
waterMaterial.backdropNode = depthEffect.mix( viewportSharedTexture(), viewportTexture.mul( depthRefraction.mix( 1, waterColor ) ) );
waterMaterial.backdropAlphaNode = depthRefraction.oneMinus();
waterMaterial.transparent = true;

const water = new THREE.Mesh( new THREE.BoxGeometry( 50, .001, 50 ), waterMaterial );
water.position.set( 0, .8, 0 );
water.position.set( 0, 0, 0 );
scene.add( water );

// floor
Expand Down Expand Up @@ -197,20 +210,38 @@
stats = new Stats();
document.body.appendChild( stats.dom );

const controls = new OrbitControls( camera, renderer.domElement );
controls = new OrbitControls( camera, renderer.domElement );
controls.minDistance = 1;
controls.maxDistance = 10;
controls.maxPolarAngle = Math.PI * 0.9;
controls.target.set( 0, 1, 0 );
controls.autoRotate = true;
controls.autoRotateSpeed = 1;
controls.target.set( 0, .2, 0 );
controls.update();

// gui

const gui = new GUI();

floorPosition = new THREE.Vector3( 0, 1, 0 );
floorPosition = new THREE.Vector3( 0, .2, 0 );

gui.add( floorPosition, 'y', - 1, 1, .001 ).name( 'position' );

gui.add( floorPosition, 'y', 0, 2, .001 ).name( 'position' );
// post processing

const scenePass = pass( scene, camera );
const scenePassColor = scenePass.getTextureNode();
const scenePassDepth = scenePass.getDepthNode().remapClamp( .3, .5 );

const waterMask = objectPosition( camera ).y.greaterThan( 0 );

const scenePassColorBlurred = scenePassColor.gaussianBlur();
scenePassColorBlurred.directionNode = waterMask.cond( scenePassDepth, scenePass.getDepthNode().mul( 5 ) );

const vignet = viewportTopLeft.distance( .5 ).mul( 1.35 ).clamp().oneMinus();

postProcessing = new PostProcessing( renderer );
postProcessing.outputNode = waterMask.cond( scenePassColorBlurred, scenePassColorBlurred.mul( color( 0x74ccf4 ) ).mul( vignet ) );

//

Expand All @@ -231,6 +262,8 @@

stats.update();

controls.update();

const delta = clock.getDelta();

floor.position.y = floorPosition.y - 5;
Expand All @@ -250,7 +283,7 @@

}

renderer.render( scene, camera );
postProcessing.render();

}

Expand Down