mirror of
https://github.com/troisjs/trois.git
synced 2024-11-24 04:12:02 +08:00
meshes
This commit is contained in:
parent
c82430eb39
commit
7cab6b5a79
@ -1,69 +0,0 @@
|
|||||||
import { defineComponent, watch } from 'vue';
|
|
||||||
import { DoubleSide, MeshBasicMaterial, PlaneGeometry, TextureLoader } from 'three';
|
|
||||||
import Mesh from './Mesh.js';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
emits: ['loaded'],
|
|
||||||
extends: Mesh,
|
|
||||||
props: {
|
|
||||||
src: String,
|
|
||||||
width: Number,
|
|
||||||
height: Number,
|
|
||||||
keepSize: Boolean,
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
this.createGeometry();
|
|
||||||
this.createMaterial();
|
|
||||||
this.initMesh();
|
|
||||||
|
|
||||||
watch(() => this.src, this.refreshTexture);
|
|
||||||
|
|
||||||
['width', 'height'].forEach(p => {
|
|
||||||
watch(() => this[p], this.resize);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (this.keepSize) this.three.onAfterResize(this.resize);
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
createGeometry() {
|
|
||||||
this.geometry = new PlaneGeometry(1, 1, 1, 1);
|
|
||||||
},
|
|
||||||
createMaterial() {
|
|
||||||
this.material = new MeshBasicMaterial({ side: DoubleSide, map: this.loadTexture() });
|
|
||||||
},
|
|
||||||
loadTexture() {
|
|
||||||
return new TextureLoader().load(this.src, this.onLoaded);
|
|
||||||
},
|
|
||||||
refreshTexture() {
|
|
||||||
if (this.texture) this.texture.dispose();
|
|
||||||
this.material.map = this.loadTexture();
|
|
||||||
this.material.needsUpdate = true;
|
|
||||||
},
|
|
||||||
onLoaded(texture) {
|
|
||||||
this.texture = texture;
|
|
||||||
this.resize();
|
|
||||||
this.$emit('loaded');
|
|
||||||
},
|
|
||||||
resize() {
|
|
||||||
if (!this.texture) return;
|
|
||||||
const screen = this.three.size;
|
|
||||||
const iW = this.texture.image.width;
|
|
||||||
const iH = this.texture.image.height;
|
|
||||||
const iRatio = iW / iH;
|
|
||||||
let w, h;
|
|
||||||
if (this.width && this.height) {
|
|
||||||
w = this.width * screen.wWidth / screen.width;
|
|
||||||
h = this.height * screen.wHeight / screen.height;
|
|
||||||
} else if (this.width) {
|
|
||||||
w = this.width * screen.wWidth / screen.width;
|
|
||||||
h = w / iRatio;
|
|
||||||
} else if (this.height) {
|
|
||||||
h = this.height * screen.wHeight / screen.height;
|
|
||||||
w = h * iRatio;
|
|
||||||
}
|
|
||||||
this.mesh.scale.x = w;
|
|
||||||
this.mesh.scale.y = h;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
__hmrId: 'Image',
|
|
||||||
});
|
|
80
src/meshes/Image.ts
Normal file
80
src/meshes/Image.ts
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
import { defineComponent, watch } from 'vue'
|
||||||
|
import { DoubleSide, MeshBasicMaterial, PlaneGeometry, Texture, TextureLoader } from 'three'
|
||||||
|
import Mesh, { MeshSetupInterface } from './Mesh'
|
||||||
|
import { object3DSetup } from '../core/Object3D'
|
||||||
|
|
||||||
|
interface ImageInterface extends MeshSetupInterface {
|
||||||
|
material?: MeshBasicMaterial
|
||||||
|
texture?: Texture
|
||||||
|
}
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
emits: ['loaded'],
|
||||||
|
extends: Mesh,
|
||||||
|
props: {
|
||||||
|
src: { type: String, required: true },
|
||||||
|
width: Number,
|
||||||
|
height: Number,
|
||||||
|
keepSize: Boolean,
|
||||||
|
},
|
||||||
|
setup(): ImageInterface {
|
||||||
|
return object3DSetup()
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.geometry = new PlaneGeometry(1, 1, 1, 1)
|
||||||
|
this.material = new MeshBasicMaterial({ side: DoubleSide, map: this.loadTexture() })
|
||||||
|
|
||||||
|
watch(() => this.src, this.refreshTexture);
|
||||||
|
|
||||||
|
['width', 'height'].forEach(p => {
|
||||||
|
// @ts-ignore
|
||||||
|
watch(() => this[p], this.resize)
|
||||||
|
})
|
||||||
|
|
||||||
|
this.resize()
|
||||||
|
if (this.keepSize) this.renderer.onResize(this.resize)
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
loadTexture() {
|
||||||
|
return new TextureLoader().load(this.src, this.onLoaded)
|
||||||
|
},
|
||||||
|
refreshTexture() {
|
||||||
|
this.texture?.dispose()
|
||||||
|
if (this.material) {
|
||||||
|
this.material.map = this.loadTexture()
|
||||||
|
this.material.needsUpdate = true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLoaded(texture: Texture) {
|
||||||
|
this.texture = texture
|
||||||
|
this.resize()
|
||||||
|
this.$emit('loaded', texture)
|
||||||
|
},
|
||||||
|
resize() {
|
||||||
|
if (!this.texture) return
|
||||||
|
const screen = this.renderer.size
|
||||||
|
const iW = this.texture.image.width
|
||||||
|
const iH = this.texture.image.height
|
||||||
|
const iRatio = iW / iH
|
||||||
|
let w = 1, h = 1
|
||||||
|
if (this.width && this.height) {
|
||||||
|
w = this.width * screen.wWidth / screen.width
|
||||||
|
h = this.height * screen.wHeight / screen.height
|
||||||
|
} else if (this.width) {
|
||||||
|
w = this.width * screen.wWidth / screen.width
|
||||||
|
h = w / iRatio
|
||||||
|
} else if (this.height) {
|
||||||
|
h = this.height * screen.wHeight / screen.height
|
||||||
|
w = h * iRatio
|
||||||
|
} else {
|
||||||
|
if (iRatio > 1) w = h * iRatio
|
||||||
|
else h = w / iRatio
|
||||||
|
}
|
||||||
|
if (this.mesh) {
|
||||||
|
this.mesh.scale.x = w
|
||||||
|
this.mesh.scale.y = h
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
__hmrId: 'Image',
|
||||||
|
})
|
@ -1,8 +1,7 @@
|
|||||||
import { ComponentPropsOptions, defineComponent, inject, watch } from 'vue'
|
import { ComponentPropsOptions, defineComponent, watch } from 'vue'
|
||||||
import { BufferGeometry, Material, Mesh as TMesh } from 'three'
|
import { BufferGeometry, Material, Mesh as TMesh } from 'three'
|
||||||
import Object3D from '../core/Object3D'
|
import Object3D, { object3DSetup, Object3DSetupInterface } from '../core/Object3D'
|
||||||
import { bindProp } from '../tools'
|
import { bindProp } from '../tools'
|
||||||
import { ThreeInterface } from '../core/useThree'
|
|
||||||
|
|
||||||
export const pointerProps = {
|
export const pointerProps = {
|
||||||
onPointerEnter: Function,
|
onPointerEnter: Function,
|
||||||
@ -14,23 +13,18 @@ export const pointerProps = {
|
|||||||
onClick: Function,
|
onClick: Function,
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MeshSetupInterface {
|
export interface MeshSetupInterface extends Object3DSetupInterface {
|
||||||
three?: ThreeInterface
|
|
||||||
mesh?: TMesh
|
mesh?: TMesh
|
||||||
geometry?: BufferGeometry
|
geometry?: BufferGeometry
|
||||||
material?: Material
|
material?: Material
|
||||||
loading?: boolean
|
loading?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MeshInterface {
|
export interface MeshInterface extends MeshSetupInterface {
|
||||||
|
setGeometry(g: BufferGeometry): void
|
||||||
setMaterial(m: Material): void
|
setMaterial(m: Material): void
|
||||||
}
|
}
|
||||||
|
|
||||||
export function defaultSetup(): MeshSetupInterface {
|
|
||||||
const three = inject('three') as ThreeInterface
|
|
||||||
return { three }
|
|
||||||
}
|
|
||||||
|
|
||||||
const Mesh = defineComponent({
|
const Mesh = defineComponent({
|
||||||
name: 'Mesh',
|
name: 'Mesh',
|
||||||
extends: Object3D,
|
extends: Object3D,
|
||||||
@ -39,10 +33,8 @@ const Mesh = defineComponent({
|
|||||||
receiveShadow: Boolean,
|
receiveShadow: Boolean,
|
||||||
...pointerProps,
|
...pointerProps,
|
||||||
},
|
},
|
||||||
setup() {
|
setup(): MeshSetupInterface {
|
||||||
return defaultSetup()
|
return object3DSetup()
|
||||||
},
|
|
||||||
created() {
|
|
||||||
},
|
},
|
||||||
provide() {
|
provide() {
|
||||||
return {
|
return {
|
||||||
@ -114,8 +106,8 @@ export function meshComponent(name, props, createGeometry) {
|
|||||||
name,
|
name,
|
||||||
extends: Mesh,
|
extends: Mesh,
|
||||||
props,
|
props,
|
||||||
setup() {
|
setup(): MeshSetupInterface {
|
||||||
return defaultSetup()
|
return object3DSetup()
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.createGeometry()
|
this.createGeometry()
|
||||||
|
@ -1,54 +0,0 @@
|
|||||||
import { defineComponent } from 'vue';
|
|
||||||
import { Sprite, SpriteMaterial, TextureLoader } from 'three';
|
|
||||||
import Object3D from '../core/Object3D';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
extends: Object3D,
|
|
||||||
emits: ['loaded'],
|
|
||||||
props: {
|
|
||||||
src: String,
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
loading: true,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
this.texture = new TextureLoader().load(this.src, this.onLoaded);
|
|
||||||
this.material = new SpriteMaterial({ map: this.texture });
|
|
||||||
this.sprite = new Sprite(this.material);
|
|
||||||
this.geometry = this.sprite.geometry;
|
|
||||||
this.initObject3D(this.sprite);
|
|
||||||
},
|
|
||||||
unmounted() {
|
|
||||||
this.texture.dispose();
|
|
||||||
this.material.dispose();
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
onLoaded() {
|
|
||||||
this.loading = false;
|
|
||||||
this.updateUV();
|
|
||||||
this.$emit('loaded');
|
|
||||||
},
|
|
||||||
updateUV() {
|
|
||||||
this.iWidth = this.texture.image.width;
|
|
||||||
this.iHeight = this.texture.image.height;
|
|
||||||
this.iRatio = this.iWidth / this.iHeight;
|
|
||||||
|
|
||||||
let x = 0.5, y = 0.5;
|
|
||||||
if (this.iRatio > 1) {
|
|
||||||
y = 0.5 / this.iRatio;
|
|
||||||
} else {
|
|
||||||
x = 0.5 / this.iRatio;
|
|
||||||
}
|
|
||||||
|
|
||||||
const positions = this.geometry.attributes.position.array;
|
|
||||||
positions[0] = -x; positions[1] = -y;
|
|
||||||
positions[5] = x; positions[6] = -y;
|
|
||||||
positions[10] = x; positions[11] = y;
|
|
||||||
positions[15] = -x; positions[16] = y;
|
|
||||||
this.geometry.attributes.position.needsUpdate = true;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
__hmrId: 'Sprite',
|
|
||||||
});
|
|
58
src/meshes/Sprite.ts
Normal file
58
src/meshes/Sprite.ts
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import { defineComponent } from 'vue'
|
||||||
|
import { Sprite, SpriteMaterial, Texture, TextureLoader } from 'three'
|
||||||
|
import Object3D, { object3DSetup, Object3DSetupInterface } from '../core/Object3D'
|
||||||
|
|
||||||
|
interface SpriteSetupInterface extends Object3DSetupInterface {
|
||||||
|
texture?: Texture
|
||||||
|
material?: SpriteMaterial
|
||||||
|
sprite?: Sprite
|
||||||
|
}
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
extends: Object3D,
|
||||||
|
emits: ['loaded'],
|
||||||
|
props: {
|
||||||
|
src: { type: String, required: true },
|
||||||
|
},
|
||||||
|
setup(): SpriteSetupInterface {
|
||||||
|
return object3DSetup()
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.texture = new TextureLoader().load(this.src, this.onLoaded)
|
||||||
|
this.material = new SpriteMaterial({ map: this.texture })
|
||||||
|
this.sprite = new Sprite(this.material)
|
||||||
|
this.initObject3D(this.sprite)
|
||||||
|
},
|
||||||
|
unmounted() {
|
||||||
|
this.texture?.dispose()
|
||||||
|
this.material?.dispose()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onLoaded() {
|
||||||
|
this.updateUV()
|
||||||
|
this.$emit('loaded')
|
||||||
|
},
|
||||||
|
updateUV() {
|
||||||
|
if (!this.texture || !this.sprite) return
|
||||||
|
|
||||||
|
const iWidth = this.texture.image.width
|
||||||
|
const iHeight = this.texture.image.height
|
||||||
|
const iRatio = iWidth / iHeight
|
||||||
|
|
||||||
|
let x = 0.5, y = 0.5
|
||||||
|
if (iRatio > 1) {
|
||||||
|
x = 0.5 * iRatio
|
||||||
|
} else {
|
||||||
|
y = 0.5 / iRatio
|
||||||
|
}
|
||||||
|
|
||||||
|
const positions = this.sprite.geometry.attributes.position.array as Array<number>
|
||||||
|
positions[0] = -x; positions[1] = -y
|
||||||
|
positions[5] = x; positions[6] = -y
|
||||||
|
positions[10] = x; positions[11] = y
|
||||||
|
positions[15] = -x; positions[16] = y
|
||||||
|
this.sprite.geometry.attributes.position.needsUpdate = true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
__hmrId: 'Sprite',
|
||||||
|
})
|
Loading…
Reference in New Issue
Block a user