更新ARhit,完成场景添加南瓜灯和绘画等操作

This commit is contained in:
rucky 2021-10-28 17:51:08 +08:00
parent 24d78f8378
commit a8cca89108
8 changed files with 973 additions and 153 deletions

View File

@ -63,7 +63,7 @@
"qrcode": "^1.4.4",
"stats.js": "^0.17.0",
"style-resources-loader": "^1.3.2",
"three": "^0.126.0",
"three": "^0.133.0",
"vue-awesome-swiper": "^4.1.1",
"vue-cli-plugin-postcss-preset": "^1.0.2",
"vue-cli-plugin-style-resources-loader": "~0.1.4",

File diff suppressed because one or more lines are too long

325
src/components/ar/hit.vue Normal file
View File

@ -0,0 +1,325 @@
<template>
<div class="c-shader" ref="container">
<div class="camra-data">
camera.position<br />
x:{{ camera ? camera.position.x : "" }} <br />
y:{{ camera ? camera.position.y : "" }} <br />
z:{{ camera ? camera.position.z : "" }} <br />
</div>
</div>
</template>
<script>
import gsap from "gsap";
import * as THREE from "three";
import * as Stats from "stats.js";
import { TubePainter } from "three/examples/jsm/misc/TubePainter.js";
import { ARButton } from "three/examples/jsm/webxr/ARButton.js";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader.js";
export default {
name: "color",
props: {
msg: String,
},
data() {
return {
remaining: 50,
container: null,
camera: null,
scene: null,
renderer: null,
reticle: null,
cursor: new THREE.Vector3(),
hitTestSource: null,
hitTestSourceRequested: false,
};
},
created() {},
mounted() {
this.initStage();
//
this.animate();
// this.addAnimation();
},
methods: {
initStage() {
//
this.container = this.$refs.container;
this.camera = new THREE.PerspectiveCamera(
70,
window.innerWidth / window.innerHeight,
0.01,
5
);
this.scene = new THREE.Scene();
// webglrender
this.renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true,
});
this.renderer.setPixelRatio(window.devicePixelRatio);
this.renderer.setSize(window.innerWidth, window.innerHeight);
this.renderer.xr.enabled = true;
if (!document.getElementById("webgl")) {
this.renderer.domElement.id = "webgl";
this.container.appendChild(this.renderer.domElement);
}
document.body.appendChild(
ARButton.createButton(this.renderer, {
requiredFeatures: ["hit-test"],
})
);
//
//
const light = new THREE.HemisphereLight(0xffffff, 0xbbbbff, 1);
light.position.set(0.5, 1, 0.25);
this.scene.add(light);
this.painter = new TubePainter();
this.painter.setSize(0.4);
// this.painter.mesh.material = new THREE.MeshLambertMaterial({
// color: 0x0f19662,
// });
this.painter.mesh.material.side = THREE.DoubleSide;
this.scene.add(this.painter.mesh);
console.log(this.painter.mesh.material);
setInterval(() => {
this.painter.mesh.material.color.set(0xffffff * Math.random());
}, 1000);
// this.addPumpkin();
let that = this;
function onSelectEnd() {
this.userData.isSelecting = false;
}
function onSelectStart() {
that.startTime = new Date().getTime();
this.userData.isSelecting = true;
this.userData.skipFrames = 2;
}
this.controller = this.renderer.xr.getController(0);
this.controller.addEventListener("select", () => {
let moved = new Date().getTime() - that.startTime > 500;
if (!moved) {
this.addPumpkin();
}
});
this.controller.addEventListener("selectstart", onSelectStart);
this.controller.addEventListener("selectend", onSelectEnd);
this.controller.userData.skipFrames = 0;
this.scene.add(this.controller);
this.reticle = new THREE.Mesh(
new THREE.RingGeometry(0.15, 0.2, 32).rotateX(-Math.PI / 2),
new THREE.MeshBasicMaterial()
);
this.reticle.matrixAutoUpdate = false;
this.reticle.visible = false;
this.scene.add(this.reticle);
//
window.addEventListener("resize", this.onWindowResize);
// this.onWindowResize();
},
addACyli() {
if (this.reticle.visible) {
const material = new THREE.MeshPhongMaterial({
color: 0xffffff * Math.random(),
});
const geometry = new THREE.CylinderGeometry(
0.1,
0.1,
0.2,
32
).translate(0, 0.1, 0);
const mesh = new THREE.Mesh(geometry, material);
mesh.position.setFromMatrixPosition(this.reticle.matrix);
mesh.scale.y = Math.random() * 2 + 1;
this.scene.add(mesh);
}
},
//
addPumpkin() {
// const dracoLoader = new DRACOLoader();
// dracoLoader.setDecoderPath("./");
// dracoLoader.setDecoderConfig({ type: "js" });
const loader = new GLTFLoader();
// loader.setDRACOLoader(dracoLoader);
loader.load(require("@/assets/model/pumpkin.gltf"), (gltf) => {
console.log(gltf);
gltf.scene.scale.set(0.1, 0.1, 0.1);
// gltf.scene.rotation.y = Math.PI;
gltf.scene.position.setFromMatrixPosition(this.reticle.matrix);
// console.log(gltf.scene);
this.scene.add(gltf.scene);
gsap.to(gltf.scene.rotation, {
y: `+=${Math.PI * 2}`,
duration: 10,
});
});
},
handleController(controller) {
const userData = controller.userData;
this.cursor
.set(0, 0, -0.2)
.applyMatrix4(this.controller.matrixWorld);
if (userData.isSelecting === true) {
if (userData.skipFrames >= 0) {
// TODO(mrdoob) Revisit this
userData.skipFrames--;
this.painter.moveTo(this.cursor);
} else {
this.painter.lineTo(this.cursor);
this.painter.update();
}
}
},
addCubes(controller) {
this.group = new THREE.Group();
// this.group.position.set(0, 0.1, 0);
for (let i = 0; i < 10; i++) {
const material = new THREE.MeshPhongMaterial({
color: 0x2399d3,
});
const geometry = new THREE.CylinderGeometry(
0.1,
0.1,
0.2,
32
).translate(0, 0.1, 0); //new THREE.BoxGeometry(1, 1, 1);
const cube = new THREE.Mesh(geometry, material);
cube.position.x = Math.random() * 4 - 2;
cube.position.y = Math.random() * 4 - 2;
cube.position.z = Math.random() * 4 - 2;
cube.scale.set(0.5, 0.5, 0.5);
// if (this.cursor)
// cube.position.setFromMatrixPosition(this.cursor.matrix);
// cube.applyMatrix4(this.controller.matrixWorld);
this.scene.add(cube);
}
// this.group.applyMatrix4(controller.matrixWorld);
// this.scene.add(this.group);
// setInterval(() => {
// console.log(this.camera.position);
// console.log(this.painter.mesh.position, 123);
// }, 5000);
},
onWindowResize(event) {
const width = window.innerWidth;
const height = window.innerHeight;
this.camera.aspect = width / height;
this.camera.updateProjectionMatrix();
this.renderer.setSize(width, height);
},
animate() {
this.renderer.setAnimationLoop(this.render);
},
render(timestamp, frame) {
this.handleController(this.controller);
if (frame) {
const referenceSpace = this.renderer.xr.getReferenceSpace();
const session = this.renderer.xr.getSession();
if (this.hitTestSourceRequested === false) {
session
.requestReferenceSpace("viewer")
.then((referenceSpace) => {
session
.requestHitTestSource({ space: referenceSpace })
.then((source) => {
this.hitTestSource = source;
});
});
session.addEventListener("end", () => {
this.hitTestSourceRequested = false;
this.hitTestSource = null;
});
this.hitTestSourceRequested = true;
}
if (this.hitTestSource) {
const hitTestResults = frame.getHitTestResults(
this.hitTestSource
);
if (hitTestResults.length) {
const hit = hitTestResults[0];
this.reticle.visible = true;
this.reticle.matrix.fromArray(
hit.getPose(referenceSpace).transform.matrix
);
} else {
this.reticle.visible = false;
}
}
}
this.renderer.render(this.scene, this.camera);
},
addAnimation() {
//
gsap.to(this.group.rotation, {
y: -Math.PI * 2,
x: 0.1,
duration: 5,
// yoyo: true,
// repeat: -1,
onUpdate: () => {
// this.renderer.toneMappingExposure = Math.pow(
// this.params.exposure,
// 4.0
// );
// this.render();
// console.log(this.params.scene);
},
});
},
},
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="less">
.c-shader {
width: 100vw;
height: 100vh;
position: relative;
z-index: 0;
.camra-data {
display: none;
.paLayout(0, 0, 150px, 80px, 10);
background: rgba(255, 255, 255, 0.75);
border-radius: 0 0 10px 0;
color: #333;
text-align: center;
line-height: 20px;
}
.select-btn {
// background-color: #fff;
.paCenterBottom(2%,50%,auto,10);
}
}
</style>

View File

@ -1,5 +1,12 @@
<template>
<div class="c-shader" ref="container"></div>
<div class="c-shader" ref="container">
<div class="camra-data">
camera.position<br />
x:{{ camera ? camera.position.x : "" }} <br />
y:{{ camera ? camera.position.y : "" }} <br />
z:{{ camera ? camera.position.z : "" }} <br />
</div>
</div>
</template>
<script>
@ -7,18 +14,9 @@ import gsap from "gsap";
import * as THREE from "three";
import * as Stats from "stats.js";
import colorVertex from "@/assets/shader/color_vertex.glsl";
import colorFrag from "@/assets/shader/color_fragment.glsl";
import pos1024 from "@/assets/layout/1024.js";
import { TubePainter } from "three/examples/jsm/misc/TubePainter.js";
import { ARButton } from "three/examples//jsm/webxr/ARButton.js";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer.js";
import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass.js";
import { ShaderPass } from "three/examples/jsm/postprocessing/ShaderPass.js";
import { UnrealBloomPass } from "three/examples/jsm/postprocessing/UnrealBloomPass.js";
export default {
name: "color",
props: {
@ -39,6 +37,8 @@ export default {
created() {},
mounted() {
this.initStage();
//
this.animate();
// this.addAnimation();
},
methods: {
@ -65,7 +65,11 @@ export default {
this.renderer.domElement.id = "webgl";
this.container.appendChild(this.renderer.domElement);
}
document.body.appendChild(ARButton.createButton(this.renderer));
document.body.appendChild(
ARButton.createButton(this.renderer, {
requiredFeatures: ["hit-test"],
})
);
//
@ -74,10 +78,13 @@ export default {
light.position.set(0, 1, 0);
this.scene.add(light);
this.painter = new TubePainter();
this.painter.setSize(0.4);
this.painter.mesh.material.side = THREE.DoubleSide;
this.scene.add(this.painter.mesh);
// this.painter = new TubePainter();
// this.painter.setSize(0.4);
// this.painter.mesh.material = new THREE.MeshLambertMaterial({
// color: 0x0189cbe,
// });
// this.painter.mesh.material.side = THREE.DoubleSide;
// this.scene.add(this.painter.mesh);
function onSelectEnd() {
this.userData.isSelecting = false;
@ -87,22 +94,86 @@ export default {
this.userData.skipFrames = 2;
}
let that = this;
function onSelect() {
that.addACyli();
}
// that.addACyli();
this.controller = this.renderer.xr.getController(0);
this.controller.addEventListener("selectstart", onSelectStart);
this.controller.addEventListener("selectend", onSelectEnd);
this.controller.addEventListener("select", onSelect);
// this.controller.addEventListener("selectstart", onSelectStart);
// this.controller.addEventListener("selectend", onSelectEnd);
this.controller.userData.skipFrames = 0;
this.scene.add(this.controller);
//
this.animate();
//
window.addEventListener("resize", this.onWindowResize);
this.onWindowResize();
// this.onWindowResize();
},
addACyli() {
const material = new THREE.MeshPhongMaterial({
color: 0xffffff * Math.random(),
});
const geometry = new THREE.CylinderGeometry(1, 1, 2, 32);
const mesh = new THREE.Mesh(geometry, material);
mesh.position.set(0, 0, -10);
this.scene.add(mesh);
},
addCubes(controller) {
this.group = new THREE.Group();
// this.group.position.set(0, 0.1, 0);
for (let i = 0; i < 10; i++) {
const material = new THREE.MeshPhongMaterial({
color: 0x2399d3,
});
const geometry = new THREE.CylinderGeometry(
0.1,
0.1,
0.2,
32
).translate(0, 0.1, 0); //new THREE.BoxGeometry(1, 1, 1);
const cube = new THREE.Mesh(geometry, material);
cube.position.x = Math.random() * 4 - 2;
cube.position.y = Math.random() * 4 - 2;
cube.position.z = Math.random() * 4 - 2;
cube.scale.set(0.5, 0.5, 0.5);
// if (this.cursor)
// cube.position.setFromMatrixPosition(this.cursor.matrix);
// cube.applyMatrix4(this.controller.matrixWorld);
this.scene.add(cube);
}
// this.group.applyMatrix4(controller.matrixWorld);
// this.scene.add(this.group);
// setInterval(() => {
// console.log(this.camera.position);
// console.log(this.painter.mesh.position, 123);
// }, 5000);
},
handleController(controller) {
const userData = controller.userData;
this.cursor.set(0, 0, -0.2).applyMatrix4(controller.matrixWorld);
this.cursor
.set(0, 0, -0.2)
.applyMatrix4(this.controller.matrixWorld);
// if (!this.group) {
// this.addCubes(controller);
// }
// this.group.position
// .set(
// this.camera.position.x,
// this.camera.position.y,
// this.camera.position.z
// )
// .applyMatrix4(controller.matrixWorld);
// console.log(this.cursor);
if (userData.isSelecting === true) {
if (userData.skipFrames >= 0) {
@ -132,7 +203,7 @@ export default {
// this.render();
},
render() {
this.handleController(this.controller);
// this.handleController(this.controller);
this.renderer.render(this.scene, this.camera);
},
@ -153,126 +224,6 @@ export default {
// console.log(this.params.scene);
},
});
//
this.group.children.map((item, index) => {
gsap.to(item.scale, {
x: "+=.5",
y: "+=.5",
z: "+=.5",
stagger: 0.01,
duration: 1,
ease: "none",
yoyoEase: "none",
yoyo: true,
repeat: 10,
});
let op = item.position;
gsap.fromTo(
item.position,
{
x: () => {
return Math.random() * 100 - 50;
},
y: () => {
return Math.random() * 100 - 50;
},
z: () => {
return Math.random() * 100 - 20;
},
},
{
x: op.x,
y: op.y,
z: op.z,
duration: 5,
onUpdate: () => {
// if (index == 1) this.render();
},
}
);
});
setTimeout(() => {
let iii = 0;
for (let ii = 0; ii < 2; ii++) {
pos1024.ready.forEach((item, index) => {
item.forEach((t, i) => {
if (t == 0) {
let position = {};
position.x = i * 10 - (item.length / 2) * 10;
position.y =
-index * 10 +
(pos1024.ready.length / 2) * 10;
position.z = ii * 10;
gsap.to(this.group.children[iii].position, {
x: position.x,
y: position.y,
z: position.z,
duration: 1,
});
iii++;
}
});
});
}
this.group.children.forEach((item, index) => {
if (index >= iii) {
gsap.to(item.position, {
x: 10000,
y: 10000,
z: 10000,
});
// gsap.to(item.scale, { x: 0, y: 0, z: 0 });
} else {
gsap.to(item.position, {
x: Math.random() * 1000 - 500,
y: Math.random() * 1000 - 500,
z: Math.random() * 1000,
duration: 2,
delay: 4,
});
gsap.to(item.scale, {
x: 0,
y: 0,
z: 0,
duration: 2.5,
delay: 4,
});
}
});
}, 6000);
// for (let ii = 0; ii < 2; ii++) {
// }
if (window.deviceInfo.device !== "PC") {
gsap.to(this.camera.position, {
z: 1200,
delay: 1,
});
gsap.to(this.camera.position, {
z: 1400,
delay: 6.5,
});
}
//
// gsap.to(this.params, {
// exposure: 1.1,
// duration: 2,
// yoyo: true,
// repeat: -1,
// onUpdate: () => {
// this.renderer.toneMappingExposure = Math.pow(
// this.params.exposure,
// 4.0
// );
// this.render();
// // console.log(this.params.scene);
// },
// });
},
},
};
@ -285,6 +236,14 @@ export default {
height: 100vh;
position: relative;
z-index: 0;
.camra-data {
.paLayout(0,0,150px,80px,10);
background: rgba(255, 255, 255, 0.75);
border-radius: 0 0 10px 0;
color: #333;
text-align: center;
line-height: 20px;
}
.select-btn {
// background-color: #fff;
.paCenterBottom(2%,50%,auto,10);

View File

@ -0,0 +1,40 @@
<!--
* @Author: your name
* @Date: 2020-08-28 15:20:15
* @LastEditTime: 2020-10-10 17:19:06
* @LastEditors: Please set LastEditors
* @Description: In User Settings Edit
* @FilePath: /xfhd-vue-scaffold/src/page/index/Home/Index.vue
-->
<template>
<div class="color">
<AR></AR>
</div>
</template>
<script>
// @ is an alias to /src
import AR from "@/components/ar/hit.vue";
export default {
name: "arHit",
components: { AR },
mounted() {},
methods: {
showTips() {
this.$weui.topTips("正在努力开发中……敬请期待", {
duration: 1500,
className: "custom-classname",
callback: function () {
// console.log('close');
},
});
},
},
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="less">
.color {
min-height: 100vh;
}
</style>

View File

@ -30,7 +30,6 @@
<p class="weui-grid__label">Color</p>
</div>
<div
href="#"
style="opacity: 0.5"
@click="jump(2)"
class="weui-grid link"
@ -40,17 +39,12 @@
</div>
<p class="weui-grid__label">AR Paint</p>
</div>
<a
href="#"
style="opacity: 0.5"
@click="showTips"
class="weui-grid"
>
<div style="opacity: 0.5" @click="jump(3)" class="weui-grid">
<div class="weui-grid__icon">
<span class="iconfont">&#xe614;</span>
</div>
<p class="weui-grid__label">预留</p>
</a>
<p class="weui-grid__label">AR HIT</p>
</div>
<a
href="#"
class="weui-grid"
@ -120,6 +114,11 @@ export default {
name: "AR",
params: {},
});
} else if (id == 3) {
this.$router.push({
name: "ARHit",
params: {},
});
}
},
showTips() {

View File

@ -11,6 +11,8 @@ import VueRouter from 'vue-router'
import Home from '../Home/index.vue'
import Color from '../Color/index.vue'
import AR from '../AR/index.vue'
import ARHit from '../ARHit/index.vue'
Vue.use(VueRouter)
@ -51,6 +53,15 @@ const routes = [
keepAlive: false, // 是否保持活跃
},
},
{
path: "/arHit",
name: "ARHit",
component: ARHit,
meta: {
title: "AR Hit Test", // 标题
keepAlive: false, // 是否保持活跃
},
},
// {
// path: "/example",
// name: "example",

View File

@ -83,7 +83,19 @@ module.exports = {
logged: true
})]
config.module.rules.push({
config.module.rules.push(
//模型加载
{
test: /\.(stl|obj|fbx|mtl|glb|gltf)?$/,
use: [
{
loader: 'file-loader', // 解决glsl 加载问题
options: {
name: './static/model/[name].[ext]'
}
}
]
}, {
test: /\.glsl$/,
use: [{
loader: 'webpack-glsl-loader', // 解决glsl 加载问题