0
点赞
收藏
分享

微信扫一扫

STM32F4系列单片机新玩法---Micropython--pyBoard

天际孤狼 2024-11-28 阅读 10

12.Three.js纹理动画与动效墙案例

在Three.js的数字孪生场景应用中,我们通常会使用到一些动画渲染效果,如动效墙,飞线、雷达等等,今天主要了解一下其中一种动画渲染效果:纹理动画。下面实现以下动效墙效果(警戒墙动画)。根据该案例的实现思路还可以实现很多种动画效果。

在这里插入图片描述

1.纹理贴图和纹理动画

首先了解一下Three.js纹理贴图相关的类 Texture,构造函数如下:

Texture( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace )

该api用于是一个纹理贴图对象,可以将其应用到一个表面,或者作为反射/折射贴图。

一般通过TextureLoader方式加载和创建:

const texture = new THREE.TextureLoader().load( "textures/water.jpg" );
texture.wrapS = THREE.RepeatWrapping; //水平方向重复包裹
texture.wrapT = THREE.RepeatWrapping; //垂直方向重复包裹
texture.repeat.set( 4, 4 );

参数说明:

wrapS:这个值定义了纹理贴图在水平方向上将如何包裹

wrapT:这个值定义了纹理贴图在垂直方向上将如何包裹

方法说明:

texture.repeat.set( 4, 4 ): 设定在水平、垂直方向上的重复次数

在我们给网格模型设置材质的时候,除了可以设置通用的基础材质或者兰伯特材质,还可以加上我们的纹理贴图,为网格模型套上”皮肤“

let texture;
function initObject() {
const geometry = new THREE.PlaneGeometry(600, 100 );

texture = new THREE.TextureLoader().load( "./img/warning.png" );
texture.repeat.set( 5, 1 );
// 设置.wrapS也就是U方向,纹理映射模式(包裹模式)
texture.wrapS = THREE.RepeatWrapping;//对应offste.x偏移
// 设置.wrapT也就是V方向,纹理映射模式
texture.wrapT = THREE.RepeatWrapping;//对应offste.y偏移

let material = new THREE.MeshBasicMaterial({
map: texture,
color: "#FFFFFF",
side: THREE.DoubleSide,
transparent:true
});

let mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
mesh.rotateX(Math.PI/2);
scene.add(mesh);
}

在这里插入图片描述

2.纹理对象.offset属性

纹理对象Texture的.offset的功能是偏移贴图在Mesh上位置,本质上相当于修改了UV顶点坐标。

texture.offset.x +=0.5;//纹理U方向偏移
texture.offset.y +=0.5;//纹理V方向偏移

该属性结合渲染循环,动态的修改uv坐标就可以实现uv动画了

// 渲染循环
function render() {
texture.offset.x +=0.001;//设置纹理动画:偏移量根据纹理和动画需要,设置合适的值
renderer.render(scene, camera);
requestAnimationFrame(render);
}
render();

3.基于平面几何体的动效墙效果代码

<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<title>Three框架</title>
<script src="../three.js-master/build/three.js"></script>
<script src="../three.js-master/examples/js/controls/OrbitControls.js"></script>
<script src="../three.js-master/examples/js/loaders/GLTFLoader.js"></script>
<script src="../three.js-master/examples/js/loaders/OBJLoader.js"></script>
<script src="../three.js-master/examples/js/loaders/MTLLoader.js"></script>
<style type="text/css">
body {
margin: 0;
padding: 0;
overflow-y: hidden;
overflow-x: hidden;
}

div#webgl {
width: 100vw;
height: 100vh;
}
</style>
<script>
var renderer;
function initThree() {
let dom = document.getElementById("webgl");
width = dom.clientWidth;
height = dom.clientHeight;
renderer = new THREE.WebGLRenderer({
antialias: true,
});
renderer.setSize(width, height);
dom.appendChild(renderer.domElement);
renderer.setClearColor("#ffffff", 1.0);
}

var camera;
function initCamera() {
camera = new THREE.PerspectiveCamera(45, width / height, 1, 10000);
// camera = new THREE.OrthographicCamera( width/-2, width/2, height/2, height/-2, 1, 10000 );
camera.position.x = 0;
camera.position.y = 1000;
camera.position.z = 0;
camera.up.x = 0;
camera.up.y = 0;
camera.up.z = 1;
camera.lookAt({
x: 0,
y: 0,
z: 0,
});
}

var scene;
function initScene() {
scene = new THREE.Scene();
}

var light;
function initLight() {
light = new THREE.DirectionalLight(0xffffff, 1.0);
light.position.set(100, 100, 200);
scene.add(light);
}

let texture;
function initObject() {
const geometry = new THREE.PlaneGeometry(600, 100 );

texture = new THREE.TextureLoader().load( "./img/warning.png" );
texture.repeat.set( 5, 1 );
// 设置.wrapS也就是U方向,纹理映射模式(包裹模式)
texture.wrapS = THREE.RepeatWrapping;//对应offste.x偏移
// 设置.wrapT也就是V方向,纹理映射模式
texture.wrapT = THREE.RepeatWrapping;//对应offste.y偏移

let material = new THREE.MeshBasicMaterial({
map: texture,
color: "#FFFFFF",
side: THREE.DoubleSide,
transparent:true
});

let mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
mesh.rotateX(Math.PI/2);
scene.add(mesh);
}

function threeStart() {
initThree(); //初始化Three.js渲染器等初始操作
initCamera(); //初始化相机
initScene(); //初始化场景
initLight(); //初始化灯光
initControls(); //初始化控制器
initObject(); //初始化渲染物体
initAxesHelper();
render(); //执行渲染
}

function initAxesHelper() {
// AxesHelper:辅助观察的坐标系(红x、绿y、蓝z)
const axesHelper = new THREE.AxesHelper(1500);
scene.add(axesHelper);
}

function initControls() {
// 设置相机控件轨道控制器OrbitControls
const controls = new THREE.OrbitControls(camera, renderer.domElement);
// 如果OrbitControls改变了相机参数,重新调用渲染器渲染三维场景
controls.addEventListener("change", function () {
renderer.render(scene, camera); //执行渲染操作
}); //监听鼠标、键盘事件
}

function render() {
// texture.offset.x -=0.01;//设置纹理动画:偏移量根据纹理和动画需要,设置合适的值
renderer.render(scene, camera);
requestAnimationFrame(render);
}
</script>
</head>

<body onload="threeStart();">
<div id="webgl"></div>
</body>

</html>

4.通过坐标的自定义几何体创建的动效墙效果

<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<title>Three框架</title>
<script src="../three.js-master/build/three.js"></script>
<script src="../three.js-master/examples/js/controls/OrbitControls.js"></script>
<script src="../three.js-master/examples/js/loaders/GLTFLoader.js"></script>
<script src="../three.js-master/examples/js/loaders/OBJLoader.js"></script>
<script src="../three.js-master/examples/js/loaders/MTLLoader.js"></script>
<style type="text/css">
body {
margin: 0;
padding: 0;
overflow-y: hidden;
overflow-x: hidden;
}

div#webgl {
width: 100vw;
height: 100vh;
}
</style>
<script>
var renderer;
function initThree() {
let dom = document.getElementById("webgl");
width = dom.clientWidth;
height = dom.clientHeight;
renderer = new THREE.WebGLRenderer({
antialias: true,
});
renderer.setSize(width, height);
dom.appendChild(renderer.domElement);
renderer.setClearColor("#ffffff", 1.0);
}

var camera;
function initCamera() {
camera = new THREE.PerspectiveCamera(45, width / height, 1, 10000);
// camera = new THREE.OrthographicCamera( width/-2, width/2, height/2, height/-2, 1, 10000 );
camera.position.x = 0;
camera.position.y = 1000;
camera.position.z = 0;
camera.up.x = 0;
camera.up.y = 0;
camera.up.z = 1;
camera.lookAt({
x: 0,
y: 0,
z: 0,
});
}

var scene;
function initScene() {
scene = new THREE.Scene();
}

var light;
function initLight() {
light = new THREE.DirectionalLight(0xffffff, 1.0);
light.position.set(100, 100, 200);
scene.add(light);
}

let texture;
function initObject() {
let c = [
100,100, //第一个点
-100,100, //第二个点
-100,-100,
100,-100,
100,100
]

let posArr = [];
let uvrr = [];
let h = 50; //围墙拉伸高度
for (let i = 0; i < c.length - 2; i += 2) {
// 围墙多边形上两个点构成一个直线扫描出来一个高度为h的矩形
// 矩形的三角形1
posArr.push(c[i], c[i + 1], 0, c[i + 2], c[i + 3], 0, c[i + 2], c[i + 3], h);
// 矩形的三角形2
posArr.push(c[i], c[i + 1], 0, c[i + 2], c[i + 3], h, c[i], c[i + 1], h);

// 注意顺序问题,和顶点位置坐标对应
uvrr.push(0, 0, 1, 0, 1, 1);
uvrr.push(0, 0, 1, 1, 0, 1);
}
let geometry = new THREE.BufferGeometry(); //声明一个空几何体对象
// 设置几何体attributes属性的位置position属性
geometry.attributes.position = new THREE.BufferAttribute(new Float32Array(posArr), 3);
// 设置几何体attributes属性的位置uv属性
geometry.attributes.uv = new THREE.BufferAttribute(new Float32Array(uvrr), 2);
geometry.computeVertexNormals()


texture = new THREE.TextureLoader().load( "./img/warning.png" );
// texture = new THREE.TextureLoader().load( "./img/wall.png" );
texture.repeat.set( 5, 1 );
// 设置.wrapS也就是U方向,纹理映射模式(包裹模式)
texture.wrapS = THREE.RepeatWrapping;//对应offste.x偏移
// 设置.wrapT也就是V方向,纹理映射模式
texture.wrapT = THREE.RepeatWrapping;//对应offste.y偏移

let material = new THREE.MeshBasicMaterial({
map: texture,
color: "#FFFFFF",
side: THREE.DoubleSide,
transparent:true
});

let mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
scene.add(mesh);
mesh.rotateX(-Math.PI / 2);

}

function threeStart() {
initThree(); //初始化Three.js渲染器等初始操作
initCamera(); //初始化相机
initScene(); //初始化场景
initLight(); //初始化灯光
initControls(); //初始化控制器
initObject(); //初始化渲染物体
// initAxesHelper();
render(); //执行渲染
}

function initAxesHelper() {
// AxesHelper:辅助观察的坐标系(红x、绿y、蓝z)
const axesHelper = new THREE.AxesHelper(1500);
scene.add(axesHelper);
}

function initControls() {
// 设置相机控件轨道控制器OrbitControls
const controls = new THREE.OrbitControls(camera, renderer.domElement);
// 如果OrbitControls改变了相机参数,重新调用渲染器渲染三维场景
controls.addEventListener("change", function () {
renderer.render(scene, camera); //执行渲染操作
}); //监听鼠标、键盘事件
}

function render() {
texture.offset.x -= 0.01;//设置纹理动画:偏移量根据纹理和动画需要,设置合适的值
renderer.render(scene, camera);
requestAnimationFrame(render);
}
</script>
</head>

<body onload="threeStart();">
<div id="webgl"></div>
</body>

</html>

视频地址:https://www.bilibili.com/video/BV1K7BRYeEyq/

举报

相关推荐

0 条评论