目錄
項(xiàng)目搭建
初始化three.js基礎(chǔ)代碼
加載圖片紋理
設(shè)置著色器
今天簡(jiǎn)單實(shí)現(xiàn)一個(gè)three.js的小Demo,加強(qiáng)自己對(duì)three知識(shí)的掌握與學(xué)習(xí),只有在項(xiàng)目中才能靈活將所學(xué)知識(shí)運(yùn)用起來,話不多說直接開始。
項(xiàng)目搭建
本案例還是借助框架書寫three項(xiàng)目,借用vite構(gòu)建工具搭建vue項(xiàng)目,vite這個(gè)構(gòu)建工具如果有不了解的朋友,可以參考我之前對(duì)其講解的文章:vite腳手架的搭建與使用 。搭建完成之后,用編輯器打開該項(xiàng)目,在終端執(zhí)行 npm i 安裝一下依賴,安裝完成之后終端在安裝 npm i three 即可。
因?yàn)槲掖罱ǖ氖莢ue3項(xiàng)目,為了便于代碼的可讀性,所以我將three.js代碼單獨(dú)抽離放在一個(gè)組件當(dāng)中,在App根組件中進(jìn)入引入該組件。具體如下:
<template>
<!-- 3D圖片效果 -->
<Image3DEffect></Image3DEffect>
</template>
<script setup>
import Image3DEffect from './components/Image3DEffect.vue';
</script>
<style lang="less">
*{
margin: 0;
padding: 0;
}
</style>
初始化three.js基礎(chǔ)代碼
three.js開啟必須用到的基礎(chǔ)代碼如下:
導(dǎo)入three庫:
import * as THREE from 'three'
初始化場(chǎng)景:
const scene = new THREE.Scene()
初始化相機(jī):
// 設(shè)置相機(jī)
const camera = new THREE.PerspectiveCamera(90,window.innerWidth/window.innerHeight,0.1,1000)
camera.position.set(0,0,5)
初始化渲染器:
// 渲染器
let renderer = new THREE.WebGLRenderer({ antialias: true })
renderer.setSize(window.innerWidth,window.innerHeight)
監(jiān)聽屏幕大小的改變,修改渲染器的寬高和相機(jī)的比例:
window.addEventListener("resize",()=>{
renderer.setSize(window.innerWidth,window.innerHeight)
camera.aspect = window.innerWidth/window.innerHeight
camera.updateProjectionMatrix()
})
設(shè)置渲染函數(shù):?
// 創(chuàng)建渲染函數(shù)
const render = () => {
requestAnimationFrame(render);
renderer.render(scene, camera);
}
render();
ok,寫完基礎(chǔ)代碼之后,接下來開始具體的Demo實(shí)操。?
加載圖片紋理
這里通過TextureLoader加載各圖片紋理文件,圖片資源大家可以隨便在網(wǎng)上找一個(gè)就行,如果想要圖片資源的朋友可以在這個(gè)網(wǎng)站找找看:https://pixabay.com/zh/ ,在加載圖片紋理時(shí),我們還要加載器深度圖。
Depth Map(深度圖)是一種圖像格式,它記錄了每個(gè)像素距離相機(jī)的距離信息。深度圖可以用來表示三維場(chǎng)景中物體的距離,是3D渲染中常用的圖像格式之一。
在圖形渲染管線中,深度圖通常用于實(shí)現(xiàn)深度測(cè)試和陰影計(jì)算。深度測(cè)試是指在將三維物體渲染到屏幕上時(shí),比較每個(gè)像素的深度值(即該像素距離相機(jī)的距離),如果一個(gè)像素前面有另一個(gè)像素,則只顯示前面的像素,從而保證渲染順序的正確性。而陰影計(jì)算則是通過比較光源與物體之間的深度值,確定每個(gè)像素是否被遮擋(即在陰影中)。
生成深度圖的網(wǎng)站:LeiaPix Converter | Depth Animations ,我們直接導(dǎo)入圖片即可:
我們可以對(duì)深度圖片的相關(guān)樣式進(jìn)行修改:
最后點(diǎn)擊Depath Map? 下載深度圖片即可。
// 加載紋理
const textureLoader = new THREE.TextureLoader()
const texture = textureLoader.load("/images/woman.jpg")
const depthTexture = textureLoader.load("/images/woman_depth.jpg")
設(shè)置著色器
著色器(Shader)是一種在圖形渲染管線中運(yùn)行的程序,它可以對(duì)渲染過程中的頂點(diǎn)、像素等進(jìn)行各種計(jì)算和處理,從而實(shí)現(xiàn)各種復(fù)雜的渲染效果。
著色器通常分為兩種類型:頂點(diǎn)著色器和片元著色器。頂點(diǎn)著色器是用來計(jì)算頂點(diǎn)的位置、法線、紋理坐標(biāo)等信息,并將其傳遞給片元著色器進(jìn)行處理;片元著色器則是用來計(jì)算每個(gè)像素(片元)的顏色值,通常根據(jù)紋理、燈光、材質(zhì)等信息進(jìn)行計(jì)算,并輸出最終顏色值到屏幕上。
// 創(chuàng)建屏幕
const geomery = new THREE.PlaneGeometry(19.2,12.8)
// 創(chuàng)建鼠標(biāo)對(duì)象
const mouse = new THREE.Vector2()
// 設(shè)置著色器材質(zhì)
const material = new THREE.ShaderMaterial({
uniforms: {
uTime: { value: 0 },
uTexture: { value: texture },
uDepthTexture: { value: depthTexture },
uMouse: { value: mouse }
},
vertexShader: `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
uniform sampler2D uTexture;
uniform sampler2D uDepthTexture;
uniform vec2 uMouse;
varying vec2 vUv;
uniform float uTime;
void main() {
vec4 color = texture2D(uTexture, vUv);
vec4 depth = texture2D(uDepthTexture, vUv);
float depthValue = depth.r;
float x = vUv.x + (uMouse.x+sin(uTime))*0.01*depthValue;
float y = vUv.y + (uMouse.y+cos(uTime))*0.01*depthValue;
vec4 newColor = texture2D(uTexture, vec2(x, y));
gl_FragColor = newColor;
}
`,
})
const plane = new THREE.Mesh(geomery,material)
scene.add(plane)
最后我們?cè)O(shè)置渲染函數(shù)和監(jiān)聽事件:
// 設(shè)置渲染函數(shù)
const render = () =>{
material.uniforms.uMouse.value = mouse;
material.uniforms.uTime.value = performance.now() / 1000;
requestAnimationFrame(render)
renderer.render(scene,camera)
}
render()
// 設(shè)置鼠標(biāo)移動(dòng)監(jiān)聽事件
window.addEventListener("mousemove", (event) => {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
});
動(dòng)態(tài)圖的文件太大上傳不了glf,這里就已圖片代替了,效果就是鼠標(biāo)移動(dòng)圖片跟著輕微的移動(dòng),如果是已經(jīng)感受到上面講解到生成深度圖的網(wǎng)站的人應(yīng)該能理解我說過的話。
接下來我們可以給該3D背景圖添加點(diǎn)文字:
<template>
<div class="canvas-container" ref="screenDom"></div>
<div class="content">
<h1>學(xué)習(xí)更多前端技術(shù)</h1>
<h2>請(qǐng)關(guān)注亦世凡華、</h2>
</div>
</template>
<style lang="less">
*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
.canvas-container {
width: 100vw;
height: 100vh;
display: block;
position: fixed;
top: 0;
left: 0;
}
.content{
position: fixed;
top: 40%;
left: 20%;
}
.content h1 {
color: rgb(255, 247, 0);
font-size: 40px;
margin-bottom: 30px;
}
</style>
文章來源:http://www.zghlxwxcb.cn/news/detail-473225.html
demo做完,給出本案例的完整代碼:(獲取素材也可以私信博主)文章來源地址http://www.zghlxwxcb.cn/news/detail-473225.html
<template>
<div class="canvas-container" ref="screenDom"></div>
<div class="content">
<h1>學(xué)習(xí)更多前端技術(shù)</h1>
<h2>請(qǐng)關(guān)注亦世凡華、</h2>
</div>
</template>
<script setup>
import * as THREE from 'three'
import { ref,onMounted } from 'vue'
let screenDom = ref(null);
// 設(shè)置場(chǎng)景
const scene = new THREE.Scene()
// 設(shè)置相機(jī)
const camera = new THREE.PerspectiveCamera(90,window.innerWidth/window.innerHeight,0.1,1000)
camera.position.set(0,0,5)
// 渲染器
let renderer = new THREE.WebGLRenderer({ antialias: true })
renderer.setSize(window.innerWidth,window.innerHeight)
onMounted(()=>{
screenDom.value.appendChild(renderer.domElement);
})
// 監(jiān)聽屏幕大小變化
window.addEventListener("resize",()=>{
renderer.setSize(window.innerWidth,window.innerHeight)
camera.aspect = window.innerWidth/window.innerHeight
camera.updateProjectionMatrix()
})
// 加載紋理
const textureLoader = new THREE.TextureLoader()
const texture = textureLoader.load("/images/woman.jpg")
const depthTexture = textureLoader.load("/images/woman_depth.jpg")
// 創(chuàng)建屏幕
const geomery = new THREE.PlaneGeometry(19.2,12.8)
// 創(chuàng)建鼠標(biāo)對(duì)象
const mouse = new THREE.Vector2()
// 設(shè)置著色器材質(zhì)
const material = new THREE.ShaderMaterial({
uniforms: {
uTime: { value: 0 },
uTexture: { value: texture },
uDepthTexture: { value: depthTexture },
uMouse: { value: mouse }
},
vertexShader: `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
uniform sampler2D uTexture;
uniform sampler2D uDepthTexture;
uniform vec2 uMouse;
varying vec2 vUv;
uniform float uTime;
void main() {
vec4 color = texture2D(uTexture, vUv);
vec4 depth = texture2D(uDepthTexture, vUv);
float depthValue = depth.r;
float x = vUv.x + (uMouse.x+sin(uTime))*0.01*depthValue;
float y = vUv.y + (uMouse.y+cos(uTime))*0.01*depthValue;
vec4 newColor = texture2D(uTexture, vec2(x, y));
gl_FragColor = newColor;
}
`,
})
const plane = new THREE.Mesh(geomery,material)
scene.add(plane)
// 設(shè)置渲染函數(shù)
const render = () =>{
material.uniforms.uMouse.value = mouse;
material.uniforms.uTime.value = performance.now() / 1000;
requestAnimationFrame(render)
renderer.render(scene,camera)
}
render()
// 設(shè)置鼠標(biāo)移動(dòng)監(jiān)聽事件
window.addEventListener("mousemove", (event) => {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
});
</script>
<style lang="less">
*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
.canvas-container {
width: 100vw;
height: 100vh;
display: block;
position: fixed;
top: 0;
left: 0;
}
.content{
position: fixed;
top: 40%;
left: 20%;
}
.content h1 {
color: rgb(255, 247, 0);
font-size: 40px;
margin-bottom: 30px;
}
</style>
到了這里,關(guān)于Three.js--》實(shí)現(xiàn)圖片轉(zhuǎn)3D效果展示的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!