Three.js 假 3D 图像?

文化   2024-10-21 07:04   河南  

使用 Three.js 的 WebGL 小实验。假 3D 图像效果。

实现代码

HTML:

<canvas class="webgl"></canvas>
CSS:
* {  margin: 0;  padding: 0;}

html,body { overflow: hidden; background-color: black;}

.webgl { position: fixed; top: 0; left: 0; outline: none;}

JAVASCRIPT:

console.clear();

import * as THREE from "https://cdn.skypack.dev/three@0.129.0";import * as dat from 'https://cdn.skypack.dev/dat.gui';



/** * Variables */

// Main Settingsconst settings = { xThreshold: 20, yThreshold: 35, originalImagePath: 'https://assets.codepen.io/122136/dog-photo.jpg', depthImagePath: 'https://assets.codepen.io/122136/dog-depth-map.jpg',}

// Sizesconst sizes = { width: window.innerWidth, height: window.innerHeight}

// Image Detailslet originalImage = nulllet depthImage = nullconst originalImageDetails = { width: 0, height: 0, aspectRatio: 0,}

// Geometries and Materiallet planeGeometry = nulllet planeMaterial = nulllet plane = null

// Cursor Settingsconst cursor = { x: 0, y: 0, lerpX: 0, lerpY: 0,}



/** * Base */

// Debugconst gui = new dat.GUI()

// Canvasconst canvas = document.querySelector('canvas.webgl')

// Sceneconst scene = new THREE.Scene()



/** * Camera */

const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height, 0.1, 100)camera.position.x = 0camera.position.y = 0camera.position.z = 0.7scene.add(camera)

let fovY = camera.position.z * camera.getFilmHeight() / camera.getFocalLength();



/*** Images*/

const textureLoader = new THREE.TextureLoader()

const loadImages = () => {

if(originalImage !== null || depthImage !== null) { originalImage.dispose() depthImage.dispose() } depthImage = textureLoader.load(settings.depthImagePath)

originalImage = textureLoader.load( settings.originalImagePath, function ( tex ) { originalImageDetails.width = tex.image.width; originalImageDetails.height = tex.image.height; originalImageDetails.aspectRatio = tex.image.height / tex.image.width;

create3dImage(); resize(); } ); }

loadImages()



/** * Create 3D Image */

const create3dImage = () => { // Cleanup Geometry for GUI if(plane !== null) { planeGeometry.dispose() planeMaterial.dispose() scene.remove(plane) }

planeGeometry = new THREE.PlaneBufferGeometry(1, 1);

planeMaterial = new THREE.ShaderMaterial({ uniforms: { originalTexture: { value: originalImage }, depthTexture: { value: depthImage }, uMouse: { value: new THREE.Vector2(0, 0) }, uThreshold: { value: new THREE.Vector2(settings.xThreshold, settings.yThreshold) }, }, fragmentShader: ` precision mediump float; uniform sampler2D originalTexture; uniform sampler2D depthTexture; uniform vec2 uMouse; uniform vec2 uThreshold;

varying vec2 vUv;

vec2 mirrored(vec2 v) { vec2 m = mod(v,2.); return mix(m,2.0 - m, step(1.0 ,m)); }

void main() { vec4 depthMap = texture2D(depthTexture, mirrored(vUv)); vec2 fake3d = vec2(vUv.x + (depthMap.r - 0.5) * uMouse.x / uThreshold.x, vUv.y + (depthMap.r - 0.5) * uMouse.y / uThreshold.y);

gl_FragColor = texture2D(originalTexture,mirrored(fake3d)); } `, vertexShader: ` varying vec2 vUv;

void main() { vUv = uv;

vec4 modelViewPosition = modelViewMatrix * vec4(position, 1.0); gl_Position = projectionMatrix * modelViewPosition; } ` });

plane = new THREE.Mesh(planeGeometry, planeMaterial); scene.add(plane);}create3dImage();



/** * Add Settings to GUI */

gui.add(settings, 'originalImagePath', { Dog: 'https://assets.codepen.io/122136/dog-photo.jpg', Girl: 'https://assets.codepen.io/122136/girl-photo.jpg', Splash: 'https://assets.codepen.io/122136/splash-photo.jpg'}).onFinishChange(loadImages).name('Image')gui.add(settings, 'depthImagePath', { Dog: 'https://assets.codepen.io/122136/dog-depth-map.jpg', Girl: 'https://assets.codepen.io/122136/girl-depth-map.jpg', Splash: 'https://assets.codepen.io/122136/splash-depth-map-v1.jpg'}).onFinishChange(loadImages).name('Depth Map')gui.add(settings, 'xThreshold').min(0).max(50).step(1).onFinishChange(loadImages).name('X Threshold')gui.add(settings, 'yThreshold').min(0).max(50).step(1).onFinishChange(loadImages).name('Y Threshold')



/** * Resize */

const resize = () => {

// Update sizes sizes.width = window.innerWidth sizes.height = window.innerHeight

// Update camera camera.aspect = sizes.width / sizes.height camera.updateProjectionMatrix()

// Update Image Size if(sizes.height/sizes.width < originalImageDetails.aspectRatio) { plane.scale.set( (fovY * camera.aspect), ((sizes.width / sizes.height) * originalImageDetails.aspectRatio), 1 ); } else { plane.scale.set( (fovY / originalImageDetails.aspectRatio), fovY, 1 ); }

// Update renderer renderer.setSize(sizes.width, sizes.height) renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))}

window.addEventListener('resize', () =>{ resize()})



/** * Cursor */

window.addEventListener('mousemove', (event) =>{ cursor.x = event.clientX / sizes.width - 0.5 cursor.y = event.clientY / sizes.height - 0.5})

window.addEventListener('mouseout', (event) =>{ cursor.x = 0 cursor.y = 0})window.addEventListener('touchmove', (event) =>{ const touch = event.touches[0]; cursor.x = touch.pageX / sizes.width - 0.5; cursor.y = touch.pageY / sizes.height - 0.5;})

window.addEventListener('touchend', (event) =>{ cursor.x = 0 cursor.y = 0})



/** * Renderer */

const renderer = new THREE.WebGLRenderer({ canvas: canvas})renderer.setSize(sizes.width, sizes.height)renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))



/** * Animate */

const clock = new THREE.Clock()let previousTime = 0

const tick = () =>{ const elapsedTime = clock.getElapsedTime() const deltaTime = elapsedTime - previousTime previousTime = elapsedTime

// Set Cursor Variables const parallaxX = cursor.x * 0.5 const parallaxY = - cursor.y * 0.5

cursor.lerpX += (parallaxX - cursor.lerpX ) * 5 * deltaTime; cursor.lerpY += (parallaxY - cursor.lerpY) * 5 * deltaTime;

// Mouse Positioning Uniform Values planeMaterial.uniforms.uMouse.value = new THREE.Vector2(cursor.lerpX , cursor.lerpY)

// Render renderer.render(scene, camera)

// Call tick again on the next frame window.requestAnimationFrame(tick)}

tick()



源码:

https://codepen.io/chrisjdesigner/pen/yLzopXW


体验:

https://codepen.io/chrisjdesigner/full/yLzopXW



感谢您的阅读      

在看点赞 好文不断  

初识Threejs
初识 Three.js 的奇妙世界,走进三维空间,与小编一起拥抱前端技术,涉及WebGL、WebGPU、Threejs、Shader、GIS、VR/AR、数字孪生、3D图形学等。
 最新文章