| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
# Install dependencies (only the first time)
npm install
# Run the local server at localhost:8080
npm run dev
# Build for production in the dist/ directory
npm run buildYou can try out by clicking on this demo links:
three.js important topics - (just an example from each topic):
const scene = new THREE.Scene()const mesh = new THREE.Mesh(
new THREE.BoxGeometry(1, 1, 1),
new THREE.MeshBasicMaterial({ color: 0xff0000 })
)
scene.add(mesh)const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height)
scene.add(camera)const renderer = new THREE.WebGLRenderer({ canvas })
renderer.setSize(sizes.width, sizes.height)
renderer.render(scene, camera)new THREE.AxesHelper() // 3D helper (x: red, y: green, z: blue) like RGB
// Example
const axesHelper = new THREE.AxesHelper( 5 )
scene.add( axesHelper )cube.position.set(2, 0.7, 1) //(x, y, z)
//cube.position.x
//cube.position.y
//cube.position.z
cube.position.length() // The distance from the center of the object to the center of scene
cube.position.distanceTo(camera.position) // distance from other object
cube.position.normalize() // object comes to distance(1) from center of scenecube.scale.set(2, 0.7, 1) //(x, y, z)
//cube.scale.x
//cube.scale.y
//cube.scale.zcube.rotation.set(Math.PI, Math.PI, Math.PI) //(x, y, z)
//cube.rotation.x = Math.PI * 2 // 360deg
//cube.rotation.y = Math.PI // 180deg
//cube.rotation.z = Math.PI / 4 // 45degcube.rotation.reorder('YXZ')camera.lookAt(cube.position) // change camera position to current objectwindow.requestAnimationFrame(callback) // pass a function before print a next frame of windowDon't forget you need to render in animation function
const clock = new THREE.Clock() // for the same animation in all computer
const elapsedTime = clock.getElapsedTime() // time of reprint
mesh.position = elapsedTimeconst clock = new THREE.Clock()
let previousTime = 0
const tick = () => {
const elapsedTime = clock.getElapsedTime()
const deltaTime = elapsedTime - previousTime
previousTime = elapsedTime
mesh.rotation.x += deltaTime
}Math.sin(elapsedTime) / Math.cos(elapsedTime)import gsap from 'gsap'
gsap.to(mesh.position, { duration: 1, delay: 1, x: 2, y: '+=5', ease: 'power2.inOut' })perspectiveCamera(fov, aspect, near = 0.1 , far = 100)perspectiveCamera Parameters:
OrthograpicCamera(left, right, top, bottom, near = 0.1, far = 100)
const aspect = sizes.width / sizes.height
const camera = new THREE.OrthographicCamera( -1 * aspect, aspect, -1, 1, 0.1, 100 )import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"
const controls = new OrbitControls(camera, canvas)
controls.enableDamping = true // smooth end of moving
controls.update() // when change the controls you need update it before render (in this case "dampin" update each time in tick)//resize window
window.addEventListener('resize', () => {
// Update size
sizes.width = window.innerWidth
sizes.height = window.innerHeight
// Update Camera
camera.aspect = sizes.width / sizes.height
camera.updateProjectionMatrix()
// Update Renderer
renderer.setSize(sizes.width, sizes.height)
})renderer.setPixelRation(Math.min(window.devicePixelRation, 2))// BoxGeometry
const geometry = new THREE.BoxGeometry(1, 1, 1, 2, 2, 2)BoxGeometry Parameters:
// Wireframe
const material = new THREE.MeshBasicMaterial( {
color: 0x00ff00,
wireframe: true
} )While wandering the three.js documentation you probably came across "BufferGeometry" Buffer Geometries are more efficient and optimized but less developer friendly!
// BoxBufferGeometry
const geometry = new THREE.BoxBufferGeometry(1, 1, 1, 2, 2, 2)Create Custom Geometry:
// create a triangle
const positionsArray = new Float32Array([
0, 0, 0, // first vertical
0, 1, 0, // second vertical
1, 0, 0 // third vertical
])
const positionsAttribute = new THREE.BufferAttribute(positionsArray, 3)
const geometry = new THREE.BoxBufferGeometry()
geometry.setAttribute('position', positionsAttribute)
const material = new THREE.MeshBasicMaterial({ color: 0xff0000, wireframe: true })
const mesh = new THREE.Mesh(geometry, material)
scene.add(mesh)const geometry = new THREE.BufferGeometry()
const count = 2000
const positionsArray = new Float32Array(count * 3 * 3) // count * vertex * (x+y+z)
for(let i = 0; i < count * 3 * 3; i++) {
positionsArray[i] = (Math.random() - 0.5) * 4 // optional amounts
}
const positionsAttr = new THREE.BufferAttribute(positionsArray, 3)
geometry.setAttribute('position', positionsAttr)debug libraries:
dat.GUI:
import * as dat from 'dat.gui'
const gui = new dat.GUI()dat.GUI parameters:
/**
* GUI
*/
const gui = new dat.GUI()
// Parameters
const parameters = {
color: 0x303030,
spin: () => {
gsap.to(group.rotation, {
duration: 1, y: group.rotation.y + (Math.PI * 2)
})
}
}
// Cube Positions
gui.add(group.position, 'x').min(-3).max(3).step(0.01).name('position')
// Cube Visibility
gui.add(group, 'visible').name('box')
gui.add(mesh, 'visible').name('box inside')
gui.add(mesh2, 'visible').name('box wireframe')
// Material
gui.add(mesh2.material, 'wireframe')
// Change Color
gui.addColor(parameters, 'color')
.onChange(() => {
mesh.material.color.set(parameters.color)
})
// Functions
gui.add(parameters, 'spin').name('CLICK TO SPIN')
// Select
gui.add(renderer, 'toneMapping', {
No: THREE.NoToneMapping,
Linear: THREE.LinearToneMapping,
Reinhard: THREE.ReinhardToneMapping,
Cineon: THREE.CineonToneMapping,
ACESFilmic: THREE.ACESFilmicToneMapping,
})Press 'H' to hide the panel.
if you want the panel to be hidden at start:
gui.hide()if you want the panel to be closed at start:
const gui = new dat.GUI({ closed: true })You can drag and drop the panel to change its width You can change the default width:
const gui = new dat.GUI({ width: 400 })Github repository: dataarts/dat.gui
textures resources:
https://ambientcg.com/
https://3dtextures.me
https://www.poliigon.com
https://www.arroway-textures.ch/
you can create your own texture:
http://substance3d.com/
read the following documents to understand the textures:
https://marmoset.co/posts/basic-theory-of-physically-based-rendering/
https://marmoset.co/posts/physically-based-rendering-and-you-can-too/
load and create a texture:
const textureLoader = new THREE.TextureLoader()
const texture = textureLoader.load('/textures/door/color.jpg')
const material = new THREE.MeshBasicMaterial({ map: texture })LoadingManager
const LoadingManager = new THREE.LoadingManager()
LoadingManager.onStart = () => {
console.log('onStart')
}
LoadingManager.onProgress = () => {
console.log('onProgress')
}
LoadingManager.onLoad = () => {
console.log('onLoad')
}
LoadingManager.onError = () => {
console.log('onError')
}
const textureLoader = new THREE.TextureLoader(LoadingManager)textures some options:
colorTexture.repeat.x = 2
colorTexture.repeat.y = 3
// or
colorTexture.repeat.set( 2, 3 )
colorTexture.wrapS = THREE.MirroredRepeatWrapping
colorTexture.wrapT = THREE.RepeatWrapping
colorTexture.offset.x = 0.5
colorTexture.offset.y = 0.5
colorTexture.rotation = Math.PI / 4
colorTexture.center.x = 0.5
colorTexture.center.y = 0.5Filtering & Mipmapping:
// better for performance and sharp result
colorTexture.generateMipmaps = false
colorTexture.minFilter = THREE.NearestFilter
colorTexture.magFilter = THREE.NearestFilterFormat and Optimisation: Size , Weight, Data
materials common properties:
const material = new THREE.MeshNormalMaterial()
material.color = new THREE.Color(0x00ff00)
material.wireframe = true
material.side = THREE.DoubleSide // FrontSide(Default), BackSide, DoubleSide
material.transparent = true
material.opacity = 0.7
material.map = colorDoorTexture
material.alphaMap = alphaDoorTexture
material.flatShading = trueconst material = new THREE.MeshPhongMaterial()
material.shininess = 100
material.specular = new THREE.Color(0xff00ff)Simple Light (just for testing materials):
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5)
scene.add(ambientLight)
const pointLight = new THREE.PointLight(0xffffff, 0.5)
pointLight.position.x = 2
pointLight.position.x = 3
pointLight.position.x = 4
scene.add(pointLight)MeshStandardMaterial:
const textureLoader = new THREE.TextureLoader()
const ambientOcclusionDoorTexture = textureLoader.load('/textures/door/ambientOcclusion.jpg')
const material = new THREE.MeshStandardMaterial()
material.metalness = 0
material.roughness = 1
material.aoMapIntensity = 1
material.side = THREE.DoubleSide
material.map = colorDoorTexture
material.aoMap = ambientOcclusionDoorTexture
material.displacementMap = heightDoorTexture
material.displacementScale = 0.05
material.metalnessMap = metalnessDoorTexture
material.roughnessMap = roughnessDoorTexture
material.normalMap = normalDoorTexture
material.normalScale.set(0.5, 0.5)
material.transparent = true
material.alphaMap = alphaDoorTexture
const plane = new THREE.Mesh(
new THREE.PlaneBufferGeometry(1, 1),
material
)
plane.geometry.setAttribute(
'uv2',
new THREE.BufferAttribute(plane.geometry.attributes.uv.array, 2)
)MeshToonMaterial:
const textureLoader = new THREE.TextureLoader()
const gradientTexture = textureLoader.load('/textures/gradients/3.jpg')
gradientTexture.magFilter = THREE.NearestFilter
const material = new THREE.MeshToonMaterial({
color: parameters.materialColor,
gradientMap: gradientTexture
})const cubeTextureLoader = new THREE.CubeTextureLoader()
const environmentMapsTexture = cubeTextureLoader.load([
'/textures/environmentMaps/1/px.jpg',
'/textures/environmentMaps/1/nx.jpg',
'/textures/environmentMaps/1/py.jpg',
'/textures/environmentMaps/1/ny.jpg',
'/textures/environmentMaps/1/pz.jpg',
'/textures/environmentMaps/1/nz.jpg'
])
const material = new THREE.MeshStandardMaterial()
material.metalness = 1
material.roughness = 0
material.side = THREE.DoubleSide
material.envMap = environmentMapsTexturehttps://github.com/nidorx/matcaps
HDRIs: https://polyhaven.com/hdris/
HTRI to CubeMap: https://matheowis.github.io/HDRI-to-CubeMap/
we can convert a font with tools like: facetype.js
in this case we use three js example font
check this out: 'node_modules/three/examples/fonts/helvetiker_regular.typeface.json'
and copy this font to static directory. now you can use it:
import { FontLoader } from 'three/examples/jsm/loaders/FontLoader.js'
import { TextGeometry } from 'three/examples/jsm/geometries/TextGeometry.js'
fontLoader.load(
'/fonts/helvetiker_regular.typeface.json',
(font) => {
const textGeometry = new TextGeometry(
'Poorya & Three.js',
{
font,
size: 0.5,
height: 0.2,
curveSegments: 5,
bevelEnabled: true,
bevelThickness: 0.03,
bevelSize: 0.02,
bevelOffset: 0,
bevelSegment: 4,
}
)
const textMaterial = new THREE.MeshBasicMaterial({ wireframe: true })
const text = new THREE.Mesh(textGeometry, textMaterial)
scene.add(text)
}
)move text to center:
textGeometry.computeBoundingBox()
textGeometry.translate(
- (textGeometry.boundingBox.max.x - 0.02) * 0.5,
- (textGeometry.boundingBox.max.y - 0.02) * 0.5,
- (textGeometry.boundingBox.max.z - 0.03) * 0.5
)
// or
textGeometry.center()const ambientLight = new THREE.AmbientLight(0xffffff, 0.5)
scene.add(ambientLight)
const directionalLight = new THREE.DirectionalLight(0x00ffff, 0.3)
directionalLight.position.set(2.5, 0.25, 0)
scene.add(directionalLight)
const hemisphereLight = new THREE.HemisphereLight(0xff0000, 0x0000ff, 0.3)
scene.add(hemisphereLight)
const pointLight = new THREE.PointLight(0xff9000, 0.5, 10, 2)
pointLight.position.set(1, -0.5, 1)
scene.add(pointLight)
// * the RectAreaLight only works with MeshStandardMaterial and MeshPhysicalMaterial
const rectAreaLight = new THREE.RectAreaLight(0x4e00ff, 2, 1, 1)
rectAreaLight.position.set(-1.5, 0, 1.5)
rectAreaLight.lookAt(new THREE.Vector3())
scene.add(rectAreaLight)
const spotLight = new THREE.SpotLight(0x00ff00, 0.5, 10, Math.PI * 0.1, 0.25, 1)
spotLight.position.set(0, 2, 3)
scene.add(spotLight)
spotLight.target.position.x = -0.75
scene.add(spotLight.target)min cost: AmbientLight & HemisphereLight mid cost: DirectionalLight & PointLight max cost: SpotLight & RectAreaLight
const directionalLightHelper = new THREE.DirectionalLightHelper(directionalLight, 0.2)
scene.add(directionalLightHelper)
const hemisphereLightHelper = new THREE.HemisphereLightHelper(hemisphereLight, 0.2)
scene.add(hemisphereLightHelper)
const pointLightHelper = new THREE.PointLightHelper(pointLight, 0.2)
scene.add(pointLightHelper)
const spotLightHelper = new THREE.SpotLightHelper(spotLight)
scene.add(spotLightHelper)
spotLightHelper.color = new THREE.Color(0x00ff00)
window.requestAnimationFrame(() => spotLightHelper.update())
import { RectAreaLightHelper } from 'three/examples/jsm/helpers/RectAreaLightHelper.js'
const rectAreaLightHelper = new RectAreaLightHelper(rectAreaLight)
scene.add(rectAreaLightHelper)just working on: directionalLight, spotLight and pointLight
directionalLight.castShadow = true
directionalLight.shadow.mapSize.width = 1024
directionalLight.shadow.mapSize.height = 1024
directionalLight.shadow.camera.top = 1
directionalLight.shadow.camera.right = 1
directionalLight.shadow.camera.bottom = -1
directionalLight.shadow.camera.left = -1
directionalLight.shadow.camera.near = 0.1
directionalLight.shadow.camera.far = 5
directionalLight.shadow.radius = 10
plane.receiveShadow = true
cube.castShadow = true
renderer.shadowMap.enabled = trueconst pointLightCameraHelper = new THREE.CameraHelper(pointLight.shadow.camera)
scene.add(pointLightCameraHelper)renderer.shadowMap.enabled = true
renderer.shadowMap.type = THREE.BasicShadowMapconst ParticlesGeometry = new THREE.SphereBufferGeometry(1, 32, 32)
const ParticlesMaterial = new THREE.PointsMaterial({
size: 0.02,
sizeAttenuation: true
})
const particles = new THREE.Points(ParticlesGeometry, ParticlesMaterial)
scene.add(particles)const ParticlesGeometry = new THREE.BufferGeometry()
const count = 5000
const positions = new Float32Array(count * 3) // 3 => (x, y, z)
for (let i = 0; i < count * 3; i++) {
positions[i] = (Math.random() - 0.5) * 10
}
ParticlesGeometry.setAttribute(
'position',
new THREE.BufferAttribute(positions, 3)
)
const ParticlesMaterial = new THREE.PointsMaterial({
size: 0.02,
sizeAttenuation: true
})
const particles = new THREE.Points(ParticlesGeometry, ParticlesMaterial)
scene.add(particles)ParticlesMaterial.alphaTest = 0.001
// OR
ParticlesMaterial.depthTest = false
// OR
ParticlesMaterial.depthWrite = false // (best solution)ParticlesMaterial.depthWrite = false
ParticlesMaterial.blending = THREE.AdditiveBlendingconst colors = new Float32Array(count * 3) // 3 => (R, G, B)
for (let i = 0; i < count * 3; i++) {
colors[i] = Math.random()
}
ParticlesGeometry.setAttribute(
'color',
new THREE.BufferAttribute(colors, 3)
)
const ParticlesMaterial = new THREE.PointsMaterial({
...others,
vertexColors: true
})const clock = new THREE.Clock()
const tick = () =>
{
const elapsedTime = clock.getElapsedTime()
// Update particles
particles.rotation.y = elapsedTime * 0.2 // position / scale / rotation
// Update controls
controls.update()
// Render
renderer.render(scene, camera)
// Call tick again on the next frame
window.requestAnimationFrame(tick)
}const clock = new THREE.Clock()
const tick = () =>
{
const elapsedTime = clock.getElapsedTime()
// Update particles (bad performance)
for(let i = 0; i < count; i++) {
const i3 = i * 3 // (x, y, z)
// i3 + 0 => x
// i3 + 1 => y
// i3 + 2 => z
const x = particlesGeometry.attributes.position.array[i3] // i3 === i3 + 0 => x
particlesGeometry.attributes.position.array[i3 + 1] = Math.sin(elapsedTime + x)
}
particlesGeometry.attributes.position.needsUpdate = true
// Update controls
controls.update()
// Render
renderer.render(scene, camera)
// Call tick again on the next frame
window.requestAnimationFrame(tick)
}https://kenney.nl/assets/particle-pack
Usage example:
const rayCaster = new THREE.Raycaster()
const tick = () => {
const elapsedTime = clock.getElapsedTime()
// Update Objects
object1.position.y = Math.sin(elapsedTime * 0.3) * 1.5
object2.position.y = Math.sin(elapsedTime * 0.8) * 1.5
object3.position.y = Math.sin(elapsedTime * 1.4) * 1.5
// Cast a Ray
const reyOrigin = new THREE.Vector3(-3, 0, 0)
const rayDirection = new THREE.Vector3(1, 0, 0)
rayDirection.normalize()
rayCaster.set(reyOrigin, rayDirection)
// OR
rayCaster.setFromCamera(mouse, camera)
const objects = [object1, object2, object3]
const intersects = rayCaster.intersectObjects(objects)
for (const object of objects) {
object.material.color.set('#ffffff')
}
for (let item of intersects) {
item.object.material.color.set('#ff0000')
}
}3D libraries:
Ammo.js
Cannon.js
Oimo.js
2D libraries:
matter.js
P2.js
Planck.js
Box2D.js
npm i --save cannonWe need to create an environment just like the scene of Three.js as known as the 'world'
import CANNON from 'cannon'
// World
const world = new CANNON.World()
world.gravity.set(0, -9.82, 0)// Sphere
const sphereShape = new CANNON.Sphere(0.5)
const sphereBody = new CANNON.Body({
mass: 1,
position: new CANNON.Vec3(0, 3, 0),
shape: sphereShape
})
world.addBody(sphereBody)
// Floor
const floorShape = new CANNON.Plane()
const floorBody = new CANNON.Body({
mess: 0, // static object
shape: floorShape
// the plane don't need a position
})
// Floor Rotation
floorBody.quaternion.setFromAxisAngle(
new CANNON.Vec3(-1, 0, 0),
Math.PI * 0.5
)
world.addBody(floorBody)const clock = new THREE.Clock()
let oldElapsedTime = 0
const tick = () => {
const elapsedTime = clock.getElapsedTime()
const deltaTime = elapsedTime - oldElapsedTime
oldElapsedTime = elapsedTime
// Update Physic world
world.step(1 / 16, deltaTime, 3)
sphere.position.copy(sphereBody.position)
}two different material:
const concreteMaterial = new CANNON.Material('concrete')
const plasticMaterial = new CANNON.Material('plastic')
const concretePlasticContactMaterial = new CANNON.ContactMaterial(
concreteMaterial,
plasticMaterial,
{
friction: 0.1,
restitution: 0.7
}
)
world.addContactMaterial(concretePlasticContactMaterial)
const sphereBody = new CANNON.Body({
...,
material: plasticMaterial
})
const floorBody = new CANNON.Body({
...,
material: concreteMaterial
})the same material:
const defaultMaterial = new CANNON.Material('default')
const defaultContactMaterial = new CANNON.ContactMaterial(
defaultMaterial,
defaultMaterial,
{
friction: 0.1,
restitution: 0.7
}
)
world.addContactMaterial(defaultContactMaterial)
world.defaultContactMaterial = defaultContactMaterial
// You Don't need to add this material to each object(objectBody)// applyLocalForce
sphereBody.applyLocalForce(new CANNON.Vec3(50, 0, 0), new CANNON.Vec3(0, 0, 0))
const tick = () => {
// applyForce
sphereBody.applyForce(new CANNON.Vec3(-0.5, 0, 0), sphereBody.position)
}// Box sizes in Cannon.js is equal to half of the box sizes in three.js
const shape = new CANNON.Box(new CANNON.Vec3(width / 2, height / 2, depth / 2))
const body = new CANNON.Body({
shape,
mass: 1,
position: new CANNON.Vec3(0, 3, 0)
})
body.position.copy(position)
world.addBody(body)
const tick = () => {
// Position
box.mesh.position.copy(box.body.position)
// Rotation (we need to update the rotation for boxes)
box.mesh.quaternion.copy(box.body.quaternion)
}// Broadphase => GridBroadphase / NaiveBroadphase / SAPBroadphase
world.broadphase = new CANNON.SAPBroadphase(world) // (best performance)world.allowSleep = trueconst hitSound = new Audio('/sounds/hit.mp3')
const playHitSound = (collicion) => {
const impactStrength = collicion.contact.getImpactVelocityAlongNormal()
if(impactStrength > 0.7) {
hitSound.volume = impactStrength / 10
hitSound.currentTime = 0
hitSound.play()
}
}
body.addEventListener('collide', playHitSound)const reset = () => {
// Remove Body
body.removeEventListener('collide', playHitSound)
world.removeBody(body)
// Remove Mesh
scene.remove(mesh)
}import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
const gltfLoader = new GLTFLoader()
gltfLoader.load(
'/models/FlightHelmet/glTF/FlightHelmet.gltf',
(gltf) => {
scene.add(gltf.scene)
// OR -> better solution (smaller object)
const children = [...gltf.scene.children]
for(const child of children) {
scene.add(child)
}
}
)Draco is an open-source library for compressing and decompressing 3D geometric meshes and point clouds. It is intended to improve the storage and transmission of 3D graphics. Website | GitHub
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js'
const dracoLoader = new DRACOLoader();
// copy draco directory from 'node_modules/three/examples/js/libs/draco' to your static directory
dracoLoader.setDecoderPath('/draco/')
const gltfLoader = new GLTFLoader()
gltfLoader.setDRACOLoader(dracoLoader)
gltfLoader.load(
'/models/Duck/glTF-Draco/Duck.gltf',
(gltf) =>
{
scene.add(gltf.scene)
}
)let mixer = null
gltfLoader.load(
'/models/Fox/glTF/Fox.gltf',
(gltf) =>
{
gltf.scene.scale.set(0.025, 0.025, 0.025)
scene.add(gltf.scene)
// Animation
mixer = new THREE.AnimationMixer(gltf.scene)
const action = mixer.clipAction(gltf.animations[2])
action.play()
}
)
const tick = () => {
if(mixer)
{
mixer.update(deltaTime)
}
//...
}Renderer Physically Correct Lights
renderer.physicallyCorrectLights = true // default = falseRenderer Encoding
// all textures
renderer.outputEncoding = THREE.sRGBEncoding
// Specific Texture
environmentMapTexture.encoding = THREE.sRGBEncodingRenderer Tone Mapping
renderer.toneMapping = THREE.ACESFilmicToneMapping
renderer.toneMappingExposure = 3Antialias
const renderer = new THREE.WebGLRenderer({
canvas: canvas,
antialias: true // bad performance :((
})Shadow Acne problem (Normal Bias Light)
directionalLight.shadow.normalBias = 0.05import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer"
import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass"
const effectProcessor = new EffectComposer(renderer)
effectProcessor.setSize(sizes.width, sizes.height)
effectProcessor.setPixelRatio(Math.min(window.devicePixelRatio, 2))
const renderPass = new RenderPass(scene, camera)
effectProcessor.addPass(renderPass)
const tick = () => {
//...
// renderer.render(scene, camera)
effectProcessor.render()
}DotScreenPass
import { DotScreenPass } from "three/examples/jsm/postprocessing/DotScreenPass"
const dotScreenPass = new DotScreenPass()
effectProcessor.addPass(dotScreenPass)
// enable or disable effect
dotScreenPass.enabled = falseGlitchPass
import { GlitchPass } from "three/examples/jsm/postprocessing/GlitchPass"
const glitchPass = new GlitchPass()
glitchPass.goWild = true // show effect without break
effectProcessor.addPass(glitchPass)ShaderPass
import { ShaderPass } from "three/examples/jsm/postprocessing/ShaderPass"
import { RGBShiftShader } from "three/examples/jsm/shaders/RGBShiftShader"
const rgbShiftPass = new ShaderPass(RGBShiftShader)
effectProcessor.addPass(rgbShiftPass)UnrealBloomPass
import { UnrealBloomPass } from "three/examples/jsm/postprocessing/UnrealBloomPass"
const unrealBloomPass = new UnrealBloomPass
unrealBloomPass.strength = 0.5
unrealBloomPass.radius = 1
unrealBloomPass.threshold = 0.9
effectProcessor.addPass(unrealBloomPass)Fixing the color by Render Target
const renderTarget = new THREE.WebGLRenderTarget(
sizes.width,
sizes.height,
{
minFilter: THREE.LinearFilter,
magFilter: THREE.LinearFilter,
format: THREE.RGBAFormat,
encoding: THREE.sRGBEncoding
}
)
const effectProcessor = new EffectComposer(renderer, renderTarget)Fixing the Antialias
// using the WebGLMultisampleRenderTarget instead of WebGLRenderTarget
const renderTarget = new THREE.WebGLMultisampleRenderTarget(
// ...
)// SMAAPass
import { SMAAPass } from "three/examples/jsm/postprocessing/SMAAPass"
const smaaPass = new SMAAPass()
effectProcessor.addPass(smaaPass)Resizing
window.addEventListener('resize', () =>
{
//...
effectProcessor.setSize(sizes.width, sizes.height)
effectProcessor.setPixelRatio(Math.min(window.devicePixelRatio, 2))
})Documentation:
const material = new THREE.RawShaderMaterial({
vertexShader: `
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
attribute vec3 position;
void main() {
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 0.1);
}
`,
fragmentShader: `
precision mediump float;
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`,
// You can use 'side' and 'transparent' and 'wireframe' properties
})index.js
import testVertexShader from './shaders/test/vertex.glsl'
import testFragmentShader from './shaders/test/fragment.glsl'
const material = new THREE.RawShaderMaterial({
vertexShader: testVertexShader,
fragmentShader: testFragmentShader
})create a file with .glsl extension for vertex shader
vertex.glsl
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
attribute vec3 position;
void main() {
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 0.1);
}create a file with .glsl extension for fragment shader
fragment.glsl
precision mediump float;
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}config the bundler for glsl files
webpack.common.js
module.exports = {
module: {
rules: [
{
test: /\.(glsl|vs|fs|vert|frag)$/,
exclude: /node_modules/,
use: ['raw-loader']
}]}}The Shader language called (OpenGL Shading Language)
close to C Language
There is no console
The indentation is not essential ...
GLSL_Shaders
void main() {
// Integer & Float
float foo = -1.0;
int bar = 1;
float a = 1.5;
int b = 2;
float c = a * float(b);
// Boolian
bool x = true;
bool y = false;
// Verctor 2
vec2 test = vec2(1.0, 2.0);
vec2 test = vec2(0.0);
test.x = 1.0;
test.y = 2.0;
test *= 2.0; // result: (2.0, 4.0)
// Vector3 (just like vec2)
vec3 vertex = vec3(1.0, 0.0, 3.0);
vec3 color = vec3(0.0);
color.r = 3.0; // or color.x
color.g = 2.2; // or color.y
color.b = 2.2; // or color.z
// and you can mix them
vec2 foo = vec2(1.0, 2.0);
vec3 bar = vec3(foo, 3.0);
vec2 fooBar = bar.xy; // or bar.xz | bar.yz
// Vector4 (just like vec2 & vec3)
vec4 foo = vec4(1.0, 2.0, 3.0, 4.0); // (x, y, z, w)
float bar = foo.w;
}void justDoSomething() {
int x = 1;
int y = 3;
}
float sum(float a, float b) {
return a + b;
}
void main() {
float result = sum(1.0, 2.0);
}index.js
const geometry = new THREE.PlaneBufferGeometry(1, 1, 32, 32)
const count = geometry.attributes.position.count
const random = new Float32Array(count)
for(let i = 0; i <= random.length; i++) {
random[i] = Math.random()
}
geometry.setAttribute('aRandom', new THREE.BufferAttribute(random, 1))vertex.glsl
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
attribute vec3 position;
attribute float aRandom;
varying float vRandom;
void main() {
vec4 modelPosition = modelMatrix * vec4(position, 1.0);
modelPosition.z += aRandom * 0.1;
vec4 viewPosition = viewMatrix * modelPosition;
vec4 projectedPosition = projectionMatrix * viewPosition;
gl_Position = projectedPosition;
vRandom = aRandom;
}fragment.glsl
precision mediump float;
varying float vRandom;
void main() {
gl_FragColor = vec4(1.0, vRandom, 0.0, 1.0);
}
const textureLoader = new THREE.TextureLoader()
const flagTexture = textureLoader.load('/textures/iran-flag.jpg')
const material = new THREE.RawShaderMaterial({
// ...
uniforms: {
uFrequency: { value: new THREE.Vector4(10, 5) },
uTime: { value: 0 },
uColor: { value: new THREE.Color('orange') },
uTexture: { value: flagTexture }
}
})vertex.glsl
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
uniform vec2 uFrequency;
uniform float uTime;
attribute vec3 position;
attribute vec2 uv;
varying vec2 vUv;
void main() {
vec4 modelPosition = modelMatrix * vec4(position, 1.0);
modelPosition.z += sin(modelPosition.x * uFrequency.x - uTime) * 0.1;
modelPosition.z += sin(modelPosition.y * uFrequency.y - uTime) * 0.1;
vec4 viewPosition = viewMatrix * modelPosition;
vec4 projectedPosition = projectionMatrix * viewPosition;
gl_Position = projectedPosition;
vUv = uv;
}fragment.glsl
precision mediump float;
uniform vec3 uColor;
uniform sampler2D uTexture;
varying vec2 vUv;
void main() {
vec4 textureColor = texture2D(uTexture, vUv);
gl_FragColor = textureColor;
}remove the following uniform and attribute and precision in both shaders:
HTML
<div class="loading-bar" />CSS
.loading-bar
{
position: absolute;
top: 50%;
width: 100%;
height: 2px;
background: #ffffff;
transform: scaleX(0);
transform-origin: top left;
transition: transform 0.5s;
will-change: transform;
}
.loading-bar.ended
{
transform: scaleX(0);
transform-origin: top right;
transition: transform 1.5s ease-in-out;
}Overlay
const overlayGeometry = new THREE.PlaneGeometry(2, 2, 1, 1)
const overlayMaterial = new THREE.ShaderMaterial({
// wireframe: true,
transparent: true,
uniforms:
{
uAlpha: { value: 1 }
},
vertexShader: `
void main()
{
gl_Position = vec4(position, 1.0);
}
`,
fragmentShader: `
uniform float uAlpha;
void main()
{
gl_FragColor = vec4(0.0, 0.0, 0.0, uAlpha);
}
`
})
const overlay = new THREE.Mesh(overlayGeometry, overlayMaterial)
scene.add(overlay)Progress
const loadingBarElement = document.querySelector('.loading-bar')
const loadingManager = new THREE.LoadingManager(
// Loaded
() => {
// Wait a little (gsap.delayedCall or window.setTimeout)
gsap.delayedCall(0.5, () => {
// Animate overlay
gsap.to(overlayMaterial.uniforms.uAlpha, { duration: 3, value: 0, delay: 1 })
// Update loadingBarElement
loadingBarElement.classList.add('ended')
loadingBarElement.style.transform = ''
})
},
// Progress
(itemUrl, itemsLoaded, itemsTotal) => {
// Calculate the progress and update the loadingBarElement
const progressRatio = itemsLoaded / itemsTotal
loadingBarElement.style.transform = `scaleX(${progressRatio})`
}
)
const gltfLoader = new GLTFLoader(loadingManager)
const cubeTextureLoader = new THREE.CubeTextureLoader(loadingManager)const group = new THREE.Group()
scene.add(group)
group.add(obj1, obj2, ...[])const mouse = new THREE.Vector2()
window.addEventListener('mousemove', (event) => {
mouse.x = event.clientX / sizes.width * 2 - 1
mouse.y = - (event.clientY / sizes.height * 2 - 1)
})const fog = new THREE.Fog(0x262837, 1, 16)
scene.fog = fog
renderer.setClearColor(0x262837) // fog colorconst environmentMap = cubeTextureLoader.load([
'/textures/environmentMaps/0/px.jpg',
'/textures/environmentMaps/0/nx.jpg',
'/textures/environmentMaps/0/py.jpg',
'/textures/environmentMaps/0/ny.jpg',
'/textures/environmentMaps/0/pz.jpg',
'/textures/environmentMaps/0/nz.jpg'
])
scene.background = environmentMap
scene.environment = environmentMapconst updateAllMaterials = () =>
{
scene.traverse((child) =>
{
if(child instanceof THREE.Mesh && child.material instanceof THREE.MeshStandardMaterial)
{
child.material.envMap = environmentMap
child.material.envMapIntensity = debugObject.envMapIntensity
child.material.needsUpdate = true
}
})
}const insideColor = new THREE.Color('#ff6030')
const outsideColor = new THREE.Color('#1b3948')
const mixedColor = insideColor.clone()
mixedColor.lerp(outsideColor, alpha) // alpha: 0 to 1const cursor = new THREE.Vector2()
window.addEventListener('mousemove', (event) => {
cursor.x = (event.clientX / sizes.width) - 0.5
cursor.y = (event.clientY / sizes.height) - 0.5
})
let scrollY = window.scrollY // need update in EventListener
const objectsDistance = 4
const clock = new THREE.Clock()
const tick = () => {
const elapsedTime = clock.getElapsedTime()
const deltaTime = elapsedTime - previousTime
previousTime = elapsedTime
// Scroll
camera.position.y = - scrollY / sizes.height * objectsDistance
// Parallax
const parallaxX = cursor.x * 0.5
const parallaxY = - cursor.y * 0.5
cameraGroup.position.x += (parallaxX - cameraGroup.position.x) * 5 * deltaTime
cameraGroup.position.y += (parallaxY - cameraGroup.position.y) * 5 * deltaTime
}| Back | FazBrowse Home | New Git URL |