Skip to content

Instantly share code, notes, and snippets.

@akella
Created November 18, 2024 22:29
Show Gist options
  • Save akella/45e399776f338087d7a9d8c5c060861f to your computer and use it in GitHub Desktop.
Save akella/45e399776f338087d7a9d8c5c060861f to your computer and use it in GitHub Desktop.
WebGL vs WebGPU self shadows
import * as THREE from "three";
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
export default class Sketch {
constructor(options) {
this.scene = new THREE.Scene();
this.container = options.dom;
this.width = this.container.offsetWidth;
this.height = this.container.offsetHeight;
this.renderer = new THREE.WebGLRenderer();
this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
this.renderer.setSize(this.width, this.height);
this.renderer.setClearColor(0xeeeeee, 1);
this.renderer.shadowMap.enabled = true;
this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
this.container.appendChild(this.renderer.domElement);
this.camera = new THREE.PerspectiveCamera(
70,
this.width / this.height,
0.01,
1000
);
this.camera.position.set(-3, 6, 0);
this.controls = new OrbitControls(this.camera, this.renderer.domElement);
this.isPlaying = true;
this.addObjects();
this.resize();
this.render();
this.setupResize();
this.addLights()
}
setupResize() {
window.addEventListener("resize", this.resize.bind(this));
}
resize() {
this.width = this.container.offsetWidth;
this.height = this.container.offsetHeight;
this.renderer.setSize(this.width, this.height);
this.camera.aspect = this.width / this.height;
this.camera.updateProjectionMatrix();
}
addObjects() {
// FLOOR
let floor = new THREE.Mesh(
new THREE.PlaneGeometry(10, 10, 10, 10),
new THREE.MeshPhysicalMaterial({ })
);
floor.receiveShadow = true;
floor.castShadow = true;
floor.rotation.x = -Math.PI / 2;
this.scene.add(floor);
// NODES DISTORTION
let mat = new THREE.MeshPhysicalMaterial({
side: THREE.DoubleSide,
color: 0xffffff,
roughness: 0.3,
metalness: 0.5,
})
mat.onBeforeCompile = (shader) => {
// distort position
shader.vertexShader = shader.vertexShader.replace(
"#include <begin_vertex>",
`
#include <begin_vertex>
float distort = sin( position.x * 10. ) * 0.2;
transformed.y += distort;
`
);
}
let depthMaterial = new THREE.MeshDepthMaterial({
depthPacking: THREE.RGBADepthPacking,
});
depthMaterial.onBeforeCompile = (shader) => {
// distort position
shader.vertexShader = shader.vertexShader.replace(
"#include <begin_vertex>",
`
#include <begin_vertex>
float distort = sin( position.x * 10. ) * 0.2;
transformed.y += distort;
`
);
}
this.geometry = new THREE.PlaneGeometry(5,1, 300,30).rotateX(-Math.PI / 2);
this.sine = new THREE.Mesh(this.geometry, mat);
this.sine.customDepthMaterial = depthMaterial;
this.scene.add(this.sine);
this.sine.position.y = 0.3
this.sine.receiveShadow = true;
this.sine.castShadow = true;
// end NODES DISTORTION
this.scene.add(this.sine);
// GEOMETRY distortion
this.geometry1 = new THREE.PlaneGeometry(5,1, 300,30).rotateX(-Math.PI / 2);
let len = this.geometry1.attributes.position.count;
for (let i = 0; i < len; i++) {
let v = new THREE.Vector3();
v.fromBufferAttribute(this.geometry1.attributes.position, i);
v.y = Math.sin(v.x * 10) * 0.2;
this.geometry1.attributes.position.setXYZ(i, v.x, v.y, v.z);
}
this.sine1 = new THREE.Mesh(this.geometry1, new THREE.MeshPhysicalMaterial({ color: 0xff0000,side: THREE.DoubleSide, roughness: 0.3, metalness: 0.5 }));
this.sine1.position.y = 0.3;
this.sine1.position.z = 2;
this.sine1.receiveShadow = true;
this.sine1.castShadow = true;
this.scene.add(this.sine1);
}
addLights() {
const light1 = new THREE.AmbientLight(0xffffff, 0.5);
this.scene.add(light1);
let directionalLight = new THREE.DirectionalLight(0xffffff, 1.);
directionalLight.position.set(10,10, 10);
directionalLight.target.position.set(0, 0, 0)
directionalLight.castShadow = true;
directionalLight.shadow.bias = -0.00001;
// directionalLight.shadow.radius = 1;
// Increase shadow map size for better quality
directionalLight.shadow.mapSize.width = 2048;
directionalLight.shadow.mapSize.height = 2048;
// Adjust the shadow camera frustum
directionalLight.shadow.camera.near = 0.1;
directionalLight.shadow.camera.far = 150;
directionalLight.shadow.camera.left = -5;
directionalLight.shadow.camera.right = 5;
directionalLight.shadow.camera.top = 5;
directionalLight.shadow.camera.bottom = -5;
this.scene.add(directionalLight);
}
render() {
requestAnimationFrame(this.render.bind(this));
this.renderer.render(this.scene, this.camera);
}
}
new Sketch({
dom: document.getElementById("container")
});
import * as THREE from "three/webgpu";
import {
Fn,
positionLocal,
sin,
positionWorld
} from "three/tsl";
import { OrbitControls } from "three/examples/jsm/Addons.js";
export default class Sketch {
constructor(options) {
this.scene = new THREE.Scene();
this.container = options.dom;
this.width = this.container.offsetWidth;
this.height = this.container.offsetHeight;
this.renderer = new THREE.WebGPURenderer();
this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
this.renderer.setSize(this.width, this.height);
this.renderer.setClearColor(0xeeeeee, 1);
this.renderer.shadowMap.enabled = true;
this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
this.container.appendChild(this.renderer.domElement);
this.camera = new THREE.PerspectiveCamera(
70,
this.width / this.height,
0.1,
10
);
this.camera.position.set(-3, 6, 0);
this.controls = new OrbitControls(this.camera, this.renderer.domElement);
this.time = 0;
this.addObjects();
this.resize();
this.render();
this.setupResize();
this.addLights();
}
setupResize() {
window.addEventListener("resize", this.resize.bind(this));
}
resize() {
this.width = this.container.offsetWidth;
this.height = this.container.offsetHeight;
this.renderer.setSize(this.width, this.height);
this.camera.aspect = this.width / this.height;
this.camera.updateProjectionMatrix();
}
addObjects() {
// FLOOR
let floor = new THREE.Mesh(
new THREE.PlaneGeometry(10, 10, 10, 10),
new THREE.MeshPhysicalNodeMaterial({ })
);
floor.receiveShadow = true;
floor.castShadow = true;
floor.rotation.x = -Math.PI / 2;
this.scene.add(floor);
// NODES DISTORTION
let mat = new THREE.MeshPhysicalNodeMaterial({
side: THREE.DoubleSide,
color: 0xffffff,
roughness: 0.3,
metalness: 0.5,
})
mat.positionNode = Fn( ()=>{
const position = positionLocal.xyz.toVar();
// const elevation = terrainElevation( positionLocal.xz );
const elevation = sin( positionWorld.x.mul(10)).mul(0.2);
position.y.addAssign( elevation );
return position;
} )();
this.geometry = new THREE.PlaneGeometry(5,1, 300,30).rotateX(-Math.PI / 2);
this.sine = new THREE.Mesh(this.geometry, mat);
this.scene.add(this.sine);
this.sine.position.y = 0.3
this.sine.receiveShadow = true;
this.sine.castShadow = true;
// end NODES DISTORTION
// GEOMETRY distortion
this.geometry1 = new THREE.PlaneGeometry(5,1, 300,30).rotateX(-Math.PI / 2);
let len = this.geometry1.attributes.position.count;
for (let i = 0; i < len; i++) {
let v = new THREE.Vector3();
v.fromBufferAttribute(this.geometry1.attributes.position, i);
v.y = Math.sin(v.x * 10) * 0.2;
this.geometry1.attributes.position.setXYZ(i, v.x, v.y, v.z);
}
this.sine1 = new THREE.Mesh(this.geometry1, new THREE.MeshPhysicalNodeMaterial({ color: 0xffff00,side: THREE.DoubleSide, roughness: 0.3, metalness: 0.5 }));
this.sine1.position.y = 0.3;
this.sine1.position.z = 2;
this.sine1.receiveShadow = true;
this.sine1.castShadow = true;
this.scene.add(this.sine1);
}
addLights() {
const light1 = new THREE.AmbientLight(0xffffff, 0.5);
this.scene.add(light1);
let directionalLight = new THREE.DirectionalLight(0xffffff, 1.);
directionalLight.position.set(10,10, 10);
directionalLight.target.position.set(0, 0, 0)
directionalLight.castShadow = true;
directionalLight.shadow.bias = -0.00001;
// directionalLight.shadow.radius = 1;
// Increase shadow map size for better quality
directionalLight.shadow.mapSize.width = 2048;
directionalLight.shadow.mapSize.height = 2048;
// Adjust the shadow camera frustum
directionalLight.shadow.camera.near = 0.1;
directionalLight.shadow.camera.far = 150;
directionalLight.shadow.camera.left = -5;
directionalLight.shadow.camera.right = 5;
directionalLight.shadow.camera.top = 5;
directionalLight.shadow.camera.bottom = -5;
this.scene.add(directionalLight);
}
render() {
requestAnimationFrame(this.render.bind(this));
this.renderer.renderAsync(this.scene, this.camera);
}
}
new Sketch({
dom: document.getElementById("container")
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment