threeJS 创建视频纹理贴图(冰雪奇缘视频)
程序员文章站
2022-05-26 19:10:44
...
本例来源官方案例
效果图
总体步骤
① 创建场景和相机
②创建物体
③ 创建渲染器
html代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
html,body{
padding: 0;
margin: 0;
overflow: hidden;
}
#video{
position: fixed;
left:0;
bottom:0;
}
</style>
</head>
<body>
<div id="container">
</div>
<video id="video" loop width="400" height="300" crossOrigin="anonymous" webkit-playsinline controls="controls" autoplay="autoplay" preload>
<source src="./video/letitgo.mp4" type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"'>
</video>
<script type="module">
</script>
</body>
</html>
导入文件,创建全局变量和函数
import * as THREE from "./js/three.module.js";
import {OrbitControls} from "./js/OrbitControls.js";
import { GUI } from './js/dat.gui.module.js';
import Stats from './js/stats.module.js';
import {EffectComposer} from './js/EffectComposer.js';
import {RenderPass} from './js/RenderPass.js';
import {ShaderPass} from './js/ShaderPass.js';
import {CopyShader} from './js/CopyShader.js';
import {DotScreenPass} from './js/DotScreenPass.js';
import {FilmPass} from './js/FilmPass.js';
import {BloomPass} from './js/BloomPass.js';
let renderer,scene,camera,spotLight,status,cubeGeometry,material=[],materials=[],mesh,cube_count, h, counter = 1,meshes=[],composer;
action();
function action() {
onload();
run();
}
function onload(){
}
function run()
{
}
function onResize()
{
}
①创建场景和相机
onload函数中
let container=document.getElementById("container");//获取container
scene=new THREE.Scene();//创建场景
camera=new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,1,10000);
camera.position.set(0, 10, 40);//创建相机并设置位置
②创建物体
onload函数中
let ambientLight=new THREE.AmbientLight();//添加环境光
scene.add(ambientLight);
spotLight=new THREE.SpotLight( 0xaabbff);//添加点光源
spotLight.position.set(-100, 30,30);
spotLight.intensity=1;
scene.add(spotLight);
//let light = new THREE.DirectionalLight( 0xaabbff, 0.3 );
//light.position.x = 300;
//light.position.y = 250;
//light.position.z = - 500;
// scene.add( light );
let spotLightMesh=new THREE.Mesh(new THREE.SphereGeometry(1,20,20),new THREE.MeshBasicMaterial());
spotLight.add(spotLightMesh);
//let gridHelper=new THREE.GridHelper(30,20);
//scene.add(gridHelper);
let video=document.getElementById("video");
let videoTexture=new THREE.VideoTexture(video);
/*var texture = new THREE.VideoTexture(video);
texture.wrapS = texture.wrapT = THREE.ClampToEdgeWrapping;
texture.minFilter = THREE.LinearFilter;
var geometry = new THREE.PlaneGeometry(200, 71); //矩形平面
var material = new THREE.MeshPhongMaterial({
map: texture, // 设置纹理贴图
side:THREE.DoubleSide
}); //材质对象Material
var mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
scene.add(mesh);*/
cube_count = 0;
for(let x=0;x<20;x++)
{
for(let y=0;y<10;y++)
{
cubeGeometry=new THREE.BoxBufferGeometry(1,1,1);
let uvs=cubeGeometry.attributes.uv.array;//得到uv
for(let i=0;i<uvs.length;i+=2)
{//重新定义贴图位置
uvs[i]= ( uvs[ i ] + x ) * 1/20;
uvs[ i + 1 ] = ( uvs[ i + 1 ] +y ) * 1/10;
}
let cubeMaterial=new THREE.MeshLambertMaterial({color:0xffffff,map:videoTexture});
mesh=new THREE.Mesh(cubeGeometry,cubeMaterial);
mesh.position.x=(x-10)*1.1;//设置x轴排列
mesh.position.y=y*1.1;//设置y轴排列
mesh.position.z=0;//设置z轴排列
mesh.scale.x = mesh.scale.y = mesh.scale.z = 1;//设置x,y,z轴缩放
scene.add(mesh);
mesh.dx = 0.001 * ( 0.5 - Math.random() );//为了后期变换位置所用
mesh.dy = 0.001 * ( 0.5 - Math.random() );
meshes[ cube_count ] = mesh;
cube_count += 1;
}
}
③创建渲染器
onload函数中
let renderModel = new RenderPass( scene, camera );
//let effectBloom = new BloomPass( 1.3,1,1,10 );
//let effectFilm=new FilmPass(1,1,1,true);
//let effectDot=new DotScreenPass();
//effectDot.uniforms.scale.value=1;
let effectCopy = new ShaderPass( CopyShader );
composer = new EffectComposer( renderer );
composer.addPass( renderModel );
//composer.addPass( effectFilm );
//composer.addPass( effectBloom );
//composer.addPass( effectDot );
composer.addPass( effectCopy );
let guiControls=new function(){
this.Cube=function () {
};
this.Equirectangular=function () {
}
};
let gui=new GUI();//创建gui
gui.add(guiControls,'Cube');
gui.add(guiControls,'Equirectangular');
status=new Stats();//创建频率显示
container.appendChild(status.dom);//频率挂到左上角
let contorl=new OrbitControls(camera,renderer.domElement);//添加鼠标滚动缩放,旋转对象
window.addEventListener('resize',onResize,false);//浏览器大小改变监听
onResize函数中
function onResize() {
camera.aspect=window.innerWidth/window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth,window.innerHeight);
composer.setSize(window.innerWidth,window.innerHeight);
}
run函数中
function run() {
requestAnimationFrame(run);
if ( counter % 1000 > 200 ) {
for ( var i = 0; i < cube_count; i ++ ) {
mesh = meshes[ i ];
mesh.rotation.x += 10 * mesh.dx;
mesh.rotation.y += 10 * mesh.dy;
mesh.position.x += 200 * mesh.dx;
mesh.position.y += 200 * mesh.dy;
mesh.position.z += 400 * mesh.dx;
}
}
if ( counter % 1000 === 0 ) {
for ( var i = 0; i < cube_count; i ++ ) {
mesh = meshes[ i ];
mesh.dx *= - 1;
mesh.dy *= - 1;
}
}
counter ++;
renderer.render(scene,camera);
renderer.clear();
composer.render();
status.update();
}
总代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<title>Title</title>
<style>
html,body{
padding: 0;
margin: 0;
overflow: hidden;
}
#video{
position: fixed;
left:0;
bottom:0;
}
</style>
</head>
<body>
<div id="container">
</div>
<video id="video" loop width="400" height="300" crossOrigin="anonymous" webkit-playsinline controls="controls" autoplay="autoplay" preload>
<source src="./video/letitgo.mp4" type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"'>
</video>
<script type="module">
import * as THREE from "./js/three.module.js";
import {OrbitControls} from "./js/OrbitControls.js";
import { GUI } from './js/dat.gui.module.js';
import Stats from './js/stats.module.js';
import {EffectComposer} from './js/EffectComposer.js';
import {RenderPass} from './js/RenderPass.js';
import {ShaderPass} from './js/ShaderPass.js';
import {CopyShader} from './js/CopyShader.js';
import {DotScreenPass} from './js/DotScreenPass.js';
import {FilmPass} from './js/FilmPass.js';
import {BloomPass} from './js/BloomPass.js';
let renderer,scene,camera,spotLight,status,cubeGeometry,material=[],materials=[],mesh,cube_count, h, counter = 1,meshes=[],composer;
action();
function action() {
onload();
run();
}
function onload() {
let container=document.getElementById("container");//获取container
scene=new THREE.Scene();//创建场景
camera=new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,1,10000);
camera.position.set(0, 10, 40);//创建相机并设置位置
let ambientLight=new THREE.AmbientLight();//添加环境光
scene.add(ambientLight);
spotLight=new THREE.SpotLight( 0xaabbff);//添加点光源
spotLight.position.set(-100, 30,30);
spotLight.intensity=1;
scene.add(spotLight);
//let light = new THREE.DirectionalLight( 0xaabbff, 0.3 );
//light.position.x = 300;
//light.position.y = 250;
//light.position.z = - 500;
// scene.add( light );
let spotLightMesh=new THREE.Mesh(new THREE.SphereGeometry(1,20,20),new THREE.MeshBasicMaterial());
spotLight.add(spotLightMesh);
//let gridHelper=new THREE.GridHelper(30,20);
//scene.add(gridHelper);
let video=document.getElementById("video");
let videoTexture=new THREE.VideoTexture(video);
/*var texture = new THREE.VideoTexture(video);
texture.wrapS = texture.wrapT = THREE.ClampToEdgeWrapping;
texture.minFilter = THREE.LinearFilter;
var geometry = new THREE.PlaneGeometry(200, 71); //矩形平面
var material = new THREE.MeshPhongMaterial({
map: texture, // 设置纹理贴图
side:THREE.DoubleSide
}); //材质对象Material
var mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
scene.add(mesh);*/
cube_count = 0;
for(let x=0;x<20;x++)
{
for(let y=0;y<10;y++)
{
cubeGeometry=new THREE.BoxBufferGeometry(1,1,1);
let uvs=cubeGeometry.attributes.uv.array;//得到uv
for(let i=0;i<uvs.length;i+=2)
{//重新定义贴图位置
uvs[i]= ( uvs[ i ] + x ) * 1/20;
uvs[ i + 1 ] = ( uvs[ i + 1 ] +y ) * 1/10;
}
let cubeMaterial=new THREE.MeshLambertMaterial({color:0xffffff,map:videoTexture});
mesh=new THREE.Mesh(cubeGeometry,cubeMaterial);
mesh.position.x=(x-10)*1.1;//设置x轴排列
mesh.position.y=y*1.1;//设置y轴排列
mesh.position.z=0;//设置z轴排列
mesh.scale.x = mesh.scale.y = mesh.scale.z = 1;//设置x,y,z轴缩放
scene.add(mesh);
mesh.dx = 0.001 * ( 0.5 - Math.random() );
mesh.dy = 0.001 * ( 0.5 - Math.random() );
meshes[ cube_count ] = mesh;
cube_count += 1;
}
}
renderer=new THREE.WebGLRenderer({antialias:true});
renderer.setPixelRatio(window.devicePixelRatio);
//renderer.setClearColor(0xEEEEEE);
renderer.autoClear = false;
renderer.gammaInput=true;
renderer.gammaOutput=true;//inear转gamma
renderer.setSize(window.innerWidth,window.innerHeight);
container.appendChild(renderer.domElement);
let renderModel = new RenderPass( scene, camera );
//let effectBloom = new BloomPass( 1.3,1,1,10 );
//let effectFilm=new FilmPass(1,1,1,true);
//let effectDot=new DotScreenPass();
//effectDot.uniforms.scale.value=1;
let effectCopy = new ShaderPass( CopyShader );
composer = new EffectComposer( renderer );
composer.addPass( renderModel );
//composer.addPass( effectFilm );
//composer.addPass( effectBloom );
//composer.addPass( effectDot );
composer.addPass( effectCopy );
let guiControls=new function(){
this.Cube=function () {
};
this.Equirectangular=function () {
}
};
let gui=new GUI();//创建gui
gui.add(guiControls,'Cube');
gui.add(guiControls,'Equirectangular');
status=new Stats();//创建频率显示
container.appendChild(status.dom);//频率挂到左上角
let contorl=new OrbitControls(camera,renderer.domElement);//添加鼠标滚动缩放,旋转对象
window.addEventListener('resize',onResize,false);//浏览器大小改变监听
}
function onResize() {
camera.aspect=window.innerWidth/window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth,window.innerHeight);
composer.setSize(window.innerWidth,window.innerHeight);
}
function run() {
requestAnimationFrame(run);
if ( counter % 1000 > 200 ) {
for ( var i = 0; i < cube_count; i ++ ) {
mesh = meshes[ i ];
mesh.rotation.x += 10 * mesh.dx;
mesh.rotation.y += 10 * mesh.dy;
mesh.position.x += 200 * mesh.dx;
mesh.position.y += 200 * mesh.dy;
mesh.position.z += 400 * mesh.dx;
}
}
if ( counter % 1000 === 0 ) {
for ( var i = 0; i < cube_count; i ++ ) {
mesh = meshes[ i ];
mesh.dx *= - 1;
mesh.dy *= - 1;
}
}
counter ++;
renderer.render(scene,camera);
renderer.clear();
composer.render();
status.update();
}
</script>
</body>
</html>