本文将带您了解关于three.js的问题的新内容,同时我们还将为您解释three.js例子的相关知识,另外,我们还将为您提供关于blender建模&threejs开发初体验|大帅老猿threejs特训
本文将带您了解关于three.js的问题的新内容,同时我们还将为您解释three.js例子的相关知识,另外,我们还将为您提供关于blender建模 & threejs开发初体验 | 大帅老猿threejs特训、javascript – Three.js – 未捕获的ReferenceError:未定义THREE、Lanuch threejs with 甜甜圈| 大帅老猿threejs特训、three 元宇宙开发 | 大帅老猿threejs特训的实用信息。
本文目录一览:- three.js的问题(three.js例子)
- blender建模 & threejs开发初体验 | 大帅老猿threejs特训
- javascript – Three.js – 未捕获的ReferenceError:未定义THREE
- Lanuch threejs with 甜甜圈| 大帅老猿threejs特训
- three 元宇宙开发 | 大帅老猿threejs特训
three.js的问题(three.js例子)
@抢小孩糖吃 你好,想跟你请教个问题:我们现在需要运用web3d。实现用户DIY家居产品。实现沙发的拼装和沙发布料的选择。请问three.js能够实现吗?有没有相关的文章?谢谢blender建模 & threejs开发初体验 | 大帅老猿threejs特训
之前看到过threejs
做的各种炫酷的案例,甚是有趣,一直打算自己也能写个demo尝试下,这次就跟着教程来学习下,小小的入个门。
建模
这次是用blender
建的模,当然也可以用其他软件。
建模这个其实没啥好说的,各种细节非常琐碎,就是一个熟能生巧的过程。教程对新手还是比较友好的,每一步的具体操作,快捷键等,教程都有讲到。多看几遍视频,入门blender
建模不是问题。
也是心有点大,不想完全复制课上讲的场馆,就按自己想法搭个稍微不一样点的。那就来个大话西游(大爱紫霞)里的场景吧。
对于新手来说,建模完全就是一个缓慢而纠结的过程,遇到各种各样的问题自不必说,跟着教程一步步来就好,其中细节此处略过不表。
插一句
新手可能会遇到无法插入中文文本的问题,稍微提一下:
由于默认不支持中文,所以添加文本的时候选择下支持中文的字体(比如`Microsoft YaHei`)
然后把需要的文字从别的地方复制过来,在编辑模式下粘贴就OK了
人物
有了大概的模型后,当然想让场景能动起来,像游戏里一样,加入一个人物,并控制着四处走动,参观下场景^_^。
人物模型可以在网上白嫖找一个,比如sketchfab,此处我们先使用教程提供的模型。
一般模型荡下来时都是静态的,要想有走动的动作,还要进行骨骼绑定,之后我们可以获取到走动-walk
和静止-idle
两种动作。
绑定动作
通过threejs
中的动画混合器,可以剪辑(clip
)出上面的两种动作
然后判断键盘按下的是否是行走(w
)键来对应的播放走动-walk
或静止-idle
的模型动画
此处crossPlay
是做了一个动画切换的优化。
视角控制
像游戏里一样,视角跟随鼠标进行转动,其实是相机的视角切换,此处我们可以获取到鼠标的移动时的位置,然后计算出clientX
的差值,给予一定权重后让人物转动(rotateY
)相应角度即可。
先要把相机cameraadd
到任务模型
射线检测
此处依据Raycaster
进行了射线碰撞检测,简单来讲,就是以人物中心为起点,向各个方向发出射线,然后检测射线是否与其他物体相交,若相交再根据两个中心点距离来判断是否会发生碰撞。
结尾
blender
建模真的是细活,一点点抠,很需要耐心啊。。
以上只是一点浅见,这次课程真的是收获蛮多,希望多来点这种课程。
javascript – Three.js – 未捕获的ReferenceError:未定义THREE
提到的路线是:
var renderer = new THREE.Webglrenderer(); // I have attached the three.js library in the script tag. I don't kNow what seems to be problem. var scene = new THREE.Scene(); var camera = new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,0.1,1000); camera.position.set = (0,10); camera.lookAt(camera.position); scene.add(camera); var geometry = new THREE.Geometry(); geometry.vertices.push(new THREE.Vector3(0.0,1.0,0.0)); geometry.vertices.push(new THREE.Vector3(-1.0,-1.0,0.0)); geometry.vertices.push(new THREE.Vector3(1.0,0.0)); geometry.faces.push(new THREE.Face3(0,1,2)); var material = new THREE.BasicmeshMaterial({ color: 0xFFFFFF,side: THREE.DoubleSide }); var mesh = new THREE.Mesh(geometry,material); mesh.position.set(-1.5,0.0,4.0); scene.add(mesh); function render() { renderer.render(scene,camera); } render();
解决方法
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r79/three.min.js"></script>
Lanuch threejs with 甜甜圈| 大帅老猿threejs特训
WebGL简介
WebGL(全写Web Graphics Library)是一种3D绘图协议,这种绘图技术标准允许把JavaScript和OpenGL ES 2.0结合在一起,通过增加OpenGL ES 2.0的一个JavaScript绑定,WebGL可以为HTML5 Canvas提供硬件3D加速渲染,这样在浏览器里更流畅地展示3D场景和模型了,还能创建复杂的导航和数据视觉化。
WebGL使用需要图形学知识,对WebGL编程可以通过js和glsl两种语言。如果想直接使用WebGL,使用者可以采用着色器(Shader)用来实现图像渲染的,但对于新手来说,Shader还是困难的。这时我们可以使用Three.js来简化我们对底层图形学的开发知识,更快的上手3D开发过程。
用Threejs实现一个甜甜圈demo
- github地址
安转依赖
npm ci
import * as THREE from ''three'';
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { RGBELoader } from ''three/examples/jsm/loaders/RGBELoader'';
let mixer;
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.01, 100);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
camera.position.set(5, 10, 25);
const controls = new OrbitControls(camera, renderer.domElement);
scene.background = new THREE.Color(0.2, 0.2, 0.2);
// const ambientLight = new THREE.AmbientLight(0xffffff, 0.2);
// scene.add(ambientLight);
const directionLight = new THREE.DirectionalLight(0xffffff, 0.4);
scene.add(directionLight);
// const boxGeometry = new THREE.BoxGeometry(1,1,1);
// const boxMaterial = new THREE.MeshBasicMaterial({color: 0x00ff00});
// const boxMesh = new THREE.Mesh(boxGeometry, boxMaterial);
// scene.add(boxMesh);
new GLTFLoader().load(''../resources/models/zhanguan.glb'', (gltf) => {
// console.log(gltf);
scene.add(gltf.scene);
gltf.scene.traverse((child)=>{
// console.log(child.name);
if (child.name === ''2023'') {
const video = document.createElement(''video'');
video.src = "./resources/yanhua.mp4";
video.muted = true;
video.autoplay = "autoplay";
video.loop = true;
video.play();
const videoTexture = new THREE.VideoTexture(video);
const videoMaterial = new THREE.MeshBasicMaterial({map: videoTexture});
child.material = videoMaterial;
}
if (child.name === ''大屏幕01'') {
const video = document.createElement(''video'');
video.src = "./resources/video01.mp4";
video.muted = true;
video.autoplay = "autoplay";
video.loop = true;
video.play();
const videoTexture = new THREE.VideoTexture(video);
const videoMaterial = new THREE.MeshBasicMaterial({map: videoTexture});
child.material = videoMaterial;
}
if (child.name === ''大屏幕02'' || child.name === ''操作台屏幕'') {
const video = document.createElement(''video'');
video.src = "./resources/video01.mp4";
video.muted = true;
video.autoplay = "autoplay";
video.loop = true;
video.play();
const videoTexture = new THREE.VideoTexture(video);
const videoMaterial = new THREE.MeshBasicMaterial({map: videoTexture});
child.material = videoMaterial;
}
if (child.name === ''环形屏幕'') {
const video = document.createElement(''video'');
video.src = "./resources/video02.mp4";
video.muted = true;
video.autoplay = "autoplay";
video.loop = true;
video.play();
const videoTexture = new THREE.VideoTexture(video);
const videoMaterial = new THREE.MeshBasicMaterial({map: videoTexture});
child.material = videoMaterial;
}
if (child.name === ''柱子屏幕'') {
const video = document.createElement(''video'');
video.src = "./resources/yanhua.mp4";
video.muted = true;
video.autoplay = "autoplay";
video.loop = true;
video.play();
const videoTexture = new THREE.VideoTexture(video);
const videoMaterial = new THREE.MeshBasicMaterial({map: videoTexture});
child.material = videoMaterial;
}
})
mixer = new THREE.AnimationMixer(gltf.scene);
const clips = gltf.animations; // 播放所有动画
clips.forEach(function (clip) {
const action = mixer.clipAction(clip);
action.loop = THREE.LoopOnce;
// 停在最后一帧
action.clampWhenFinished = true;
action.play();
});
})
new RGBELoader()
.load(''../resources/sky.hdr'', function (texture) {
// scene.background = texture;
texture.mapping = THREE.EquirectangularReflectionMapping;
scene.environment = texture;
renderer.outputEncoding = THREE.sRGBEncoding;
renderer.render(scene, camera);
});
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
controls.update();
// if (donuts){
// donuts.rotation.y += 0.01;
// }
if (mixer) {
mixer.update(0.02);
}
}
animate();
最后
加入猿创营 (v:dashuailaoyuan),一起交流学习
three 元宇宙开发 | 大帅老猿threejs特训
第一课
了解 three 安装和基础应用 做了一个 甜甜圈 案例
提到 Three.js,不得不先提 OpenGL 和 WebGL,OpenGL 是一个跨平台的3D/2D的绘图标准(规范),WebGL(Web Graphics Library)是一种3D绘图协议。
WebGL允许把JavaScript和OpenGL 结合在一起运用,但使用WebGL原生的API来写3D程序非常的复杂,同时需要相对较多的数学知识,对于开发者来说学习成本非常高。
Three.js是基于webGL的封装的一个易于使用且轻量级的3D库,Three.js对WebGL提供的接口进行了非常好的封装,简化了很多细节,大大降低了学习成本,极大地提高了性能,功能也非常强大。
使用 npm 安装threejs
npm i three
然后,引入three
import * as THREE from ''three'';
整体代码
<!-- -->
<template>
<button @click="glbPlay">aaa</button>
<div id="three" ref="three">
<div ref="le" ></div>
</div>
</template>
<script setup lang="ts">
import {ref,reactive,onMounted,onUnmounted} from ''vue'';
import * as dat from ''dat.gui'';
import {
AmbientLight,
AnimationMixer,
AxesHelper,
CameraHelper,
Color,
DirectionalLight,
DirectionalLightHelper,
EquirectangularReflectionMapping,
HemisphereLight,
LoopOnce,
Mesh,
MeshLambertMaterial,
PerspectiveCamera,
PlaneGeometry,
PointLight,
Scene,
SpotLight,
sRGBEncoding,
WebGLRenderer,
} from ''three'';
import { GLTFLoader } from ''three/examples/jsm/loaders/GLTFLoader'';
import { OrbitControls } from ''three/examples/jsm/controls/OrbitControls'';
import { RGBELoader } from ''three/examples/jsm/loaders/RGBELoader'';
/**
* 配置
*/
// MARK: 配置
const le = ref();
const three = ref();
const mixer = ref();
const donuts = ref();
const action = ref();
const clips = ref();
const scene = new Scene(); // 场景对象Scene
const axes = new AxesHelper(50); // 轴长度
const th = reactive({
ctrl: new dat.GUI(),
renderer:new WebGLRenderer({
antialias: true
}), // 渲染器对象
ambienLight : new AmbientLight(0xcccccc), // 自然光
planeGeometry:new PlaneGeometry(100,100),// 地面
spotLight:new SpotLight(0xFFFFFF),// 聚光灯
pointlight:new PointLight(0xFFFFFF,6,60), // 点光源
directionalLight:new DirectionalLight(0xFFFFFF,4), // 平行光源
hemisphereLight : new HemisphereLight(0xffffff,0x00ff00,1)// 半球光光源
});
scene.background =new Color(0x333333);
scene.add(axes); // 添加轴
new RGBELoader()
.load(''./HDR/sky.hdr'', function (texture) {
scene.background = texture;
texture.mapping = EquirectangularReflectionMapping;
scene.environment = texture;
th.renderer.outputEncoding = sRGBEncoding;
th.renderer.render(scene, camera);
});
let render=()=>{
th.renderer.render(scene,camera);
}
/**
* 影相机
*/
// MARK: 影相机
// let camera = ref<PerspectiveCamera|OrthographicCamera>(new PerspectiveCamera(75,window.innerWidth/window.innerHeight,5,10000)); //透视相机
let camera = new PerspectiveCamera(75,window.innerWidth/window.innerHeight,10,1000); //透视相机
camera.position.set(-20, 20, 30);
camera.lookAt(scene.position);
/**
* 灯光
*/
// MARK: 灯光
th.spotLight.position.set(0, 30, 60);
th.spotLight.castShadow = true;
th.spotLight.intensity = 0.6; // 光照强度
// th.spotLight.shadow.mapSize = new Vector2(1024, 1024); // shadow 与计算此光照的阴影
// th.spotLight.shadow.camera.far = 130; // far:远面
// th.spotLight.shadow.camera.near = 40; // near:近面
scene.add(th.spotLight);
scene.add(th.ambienLight); // 自然光
// const pointlight = new PointLight(0xFFFFFF,6,60); // 点光源
th.pointlight.position.x = 0;
th.pointlight.position.y = 0;
th.pointlight.position.z = 5;
// scene.add(th.pointlight); // 点光源
new DirectionalLight(0xFFFFFF,4) // 平行光源
th.directionalLight.castShadow=true;
th.directionalLight.shadow.mapSize.width = 2048;
th.directionalLight.shadow.mapSize.height = 2048;
th.directionalLight.position.set(20, 20, 20);
// scene.add(th.directionalLight);
const helper =new DirectionalLightHelper(th.directionalLight,5);
// scene.add(helper);
const dirCameraHelper = new CameraHelper(th.directionalLight.shadow.camera)
// scene.add(dirCameraHelper);
const hemisphereLight = new HemisphereLight(0xffffff,0x00ff00,1);
hemisphereLight.position.set(100,50,100);
// scene.add(hemisphereLight);// 半球光光源
/**
* 渲染 场景
*/
// MARK: 渲染 场景
th.renderer.shadowMap.enabled = true;
th.renderer.setSize(window.innerWidth,window.innerHeight);
/**
* 地面
*/
// MARK: 地面
const lambertMaterial = new MeshLambertMaterial({//材质对象Lambert
color:0xcccccc
});
const plane = new Mesh(th.planeGeometry,lambertMaterial); // 网格模型
plane.rotation.x=-0.5*Math.PI;
plane.position.set(15, 0, 0);
plane.receiveShadow = true;
// scene.add(plane);
/**
* OrbitControls 轨道控制器
*/
// MARK: OrbitControls 轨道控制器
let controls = new OrbitControls(camera,th.renderer.domElement);
controls.update();
/**
* 导入模型
*/
// MARK: 导入模型
new GLTFLoader().setPath(''./model/test/'').load(''test.glb'',gltf=>{
console.log(gltf);
scene.add(gltf.scene);
donuts.value = gltf.scene;
// gltf.scene.traverse((child)=>{
// console.log(child.name);
// })
clips.value = gltf.animations; // 播放所有动画
});
let glbPlay=()=>{
mixer.value = new AnimationMixer(donuts.value);
clips.value.forEach( (clip: any)=> {
action.value = mixer.value.clipAction(clip);
action.value.loop = LoopOnce;
action.value.timeScale=1.5;
// 停在最后一帧
action.value.clampWhenFinished = true;
action.value.play();
});
}
//============================================场景搭建end==================================
onMounted(()=>{
le.value.appendChild(th.renderer.domElement);
window.addEventListener(''resize'',()=>{
camera.aspect = window.innerWidth/window.innerHeight;
camera.updateProjectionMatrix();
th.renderer.setSize(window.innerWidth,window.innerHeight);
render();
},false);
});
//============================================构建场景 start==================================
// MARK: 构建场景
//============================================构建场景 end==================================
let renderScene=():void=>{
controls.update();
requestAnimationFrame(renderScene);
render();
if (donuts.value){
donuts.value.rotation.y += 0.01;
}
if (mixer.value) {
mixer.value.update(0.02);
}
}
renderScene()
onUnmounted(()=>{
th.ctrl.destroy() // 销毁dat.GUI
});
</script>
<style scoped lang="less">
@import ''~@/common/less/index.less'';
</style>
以上代码可以直接运行,运行的效果如下
因为自己会建模,所以没有用到老师的模形
第二课
Blender 的建模基础
主要自己会建模这一课没怎么认真听
第三课
元宇宙开发
角色引入
// 角色引入
new GLTFLoader().setPath("./model/test/").load("player.glb", gltf => {
playerMesh.value = gltf.scene;
gltf.scene.position.set(0, -1.43, 14.5);
gltf.scene.rotateY(Math.PI);
gltf.scene.traverse((child)=>{
child.receiveShadow = true;
child.castShadow = true;
})
camera.position.set(0, 2.5, -4);
camera.lookAt(lookTarget);
const pointLight: PointLight = new PointLight(0xffffff, 1);
pointLight.position.set(0, 1.8, -1);
playerMixer.value = new AnimationMixer(gltf.scene);
const clipWalk = AnimationUtils.subclip(gltf.animations[0], ''walk'', 0, 30); // 走路动画
actionWalk.value = playerMixer.value.clipAction(clipWalk);
const clipIdle = AnimationUtils.subclip(gltf.animations[0], ''idle'', 31, 281); // 待机动画
actionIdle.value = playerMixer.value.clipAction(clipIdle);
actionIdle.value.play();
gltf.scene.add(pointLight);
gltf.scene.add(camera);
scene.add(gltf.scene);
});
场景搭建
// 场景的整体搭建
// 给场景上贴图 和 贴视频
new GLTFLoader().setPath("./model/test/").load("caab1.glb", (gltf) => {
// console.log(gltf);
scene.add(gltf.scene);
donuts.value = gltf.scene;
gltf.scene.traverse((child) => {
// console.log(child.name);
child.castShadow = true;
child.receiveShadow = true;
console.log(child.name);
if (child.name == "2023") {
happy.value = child;
const video = document.createElement("video");
video.src = "./img/yanhua.mp4";
video.muted = true;
video.autoplay = true;
video.loop = true;
video.play();
// console.log(document.body);
// document.body.append(video);
const videoTexture = new VideoTexture(video);
const videoMaterial = new MeshBasicMaterial({ map: videoTexture });
(child as any).material = videoMaterial;
}
if (child.name === "video1") {
const video = document.createElement("video");
video.src = "./img/video1.mp4";
video.muted = true;
video.autoplay = true;
video.loop = true;
video.play();
const videoTexture = new VideoTexture(video);
const videoMaterial = new MeshBasicMaterial({ map: videoTexture });
(child as any).material = videoMaterial;
}
if (child.name === "video2") {
const video = document.createElement("video");
video.src = "./img/video2.mp4";
video.muted = true;
video.autoplay = true;
video.loop = true;
video.play();
const videoTexture = new VideoTexture(video);
const videoMaterial = new MeshBasicMaterial({ map: videoTexture });
(child as any).material = videoMaterial;
}
if (child.name === "ccc1") {
const video = document.createElement("video");
video.src = "./img/ccc1.mp4";
video.muted = true;
video.autoplay = true;
video.loop = true;
video.play();
const videoTexture = new VideoTexture(video);
const videoMaterial = new MeshBasicMaterial({ map: videoTexture });
(child as any).material = videoMaterial;
}
if (child.name === "bbb1" || child.name === "bbb2" || child.name === "bbb3") {
const video = document.createElement("video");
video.src = "./img/bbb1.mp4";
video.muted = true;
video.autoplay = true;
video.loop = true;
video.play();
const videoTexture = new VideoTexture(video);
const videoMaterial = new MeshBasicMaterial({ map: videoTexture });
(child as any).material = videoMaterial;
}
if (child.name == "image1") {
let imageTexture = new TextureLoader().load(''./img/Cam1.jpg'');
let imageMaterial = new MeshBasicMaterial({
map:imageTexture,
side:BackSide
});
(child as any).material = imageMaterial;
}
if (child.name == "image2") {
let imageTexture = new TextureLoader().load(''./img/Cam2.jpg'');
let imageMaterial = new MeshBasicMaterial({
map:imageTexture,
side:BackSide
});
(child as any).material = imageMaterial;
}
if (child.name == "image3") {
let imageTexture = new TextureLoader().load(''./img/Came3.jpg'');
let imageMaterial = new MeshBasicMaterial({
map:imageTexture,
side:BackSide
});
(child as any).material = imageMaterial;
}
if (child.name == "image4") {
let imageTexture = new TextureLoader().load(''./img/Came4.jpg'');
let imageMaterial = new MeshBasicMaterial({
map:imageTexture,
side:BackSide
});
(child as any).material = imageMaterial;
}
});
});
碰撞检测
// 碰撞检测
window.addEventListener("keydown", (e) => {
if (e.key == "w") {
// if(playerMesh.value){
// playerMesh.value.translateZ(0.1);
// }
if(playerMesh.value){
const curPos = playerMesh.value.position.clone();
playerMesh.value.translateZ(1);
const frontPos = playerMesh.value.position.clone();
playerMesh.value.translateZ(-1);
const frontVector3 = frontPos.sub(curPos).normalize()
const raycasterFront = new Raycaster(playerMesh.value.position.clone().add(playerHalfHeight), frontVector3);
const collisionResultsFrontObjs = raycasterFront.intersectObjects(scene.children);
console.log(collisionResultsFrontObjs);
if ((collisionResultsFrontObjs && collisionResultsFrontObjs[0] && collisionResultsFrontObjs[0].distance > 1) || collisionResultsFrontObjs.length==0) {
console.log(''AAAAAAAAAAAAAAAAAAAAAAw'');
playerMesh.value.translateZ(0.1);
}
}
if (!isWalk.value) {
if( actionIdle.value && actionWalk.value){
crossPlay(actionIdle.value,actionWalk.value);
}
isWalk.value = true;
}
}
不管做什么还是要坚持,坚持才会迎来胜利。如果你有兴趣的话,也可以加入猿创营 (v:dashuailaoyuan),一起交流学习
关于three.js的问题和three.js例子的问题我们已经讲解完毕,感谢您的阅读,如果还想了解更多关于blender建模 & threejs开发初体验 | 大帅老猿threejs特训、javascript – Three.js – 未捕获的ReferenceError:未定义THREE、Lanuch threejs with 甜甜圈| 大帅老猿threejs特训、three 元宇宙开发 | 大帅老猿threejs特训等相关内容,可以在本站寻找。
本文标签: