我在访问属性方面遇到了麻烦,即使它们存在于对象中,但是打字稿告诉我他们没有。我创建了一个粒子对象,它包含形状的几何形状和材质。我需要能够访问粒子的几何顶点,但是当我尝试时,typescript会抛出一个拟合。例如,this.particles.geometry.vertices.length
应该返回我的顶点的长度,但是typescript表示顶点在几何体中实际存在时不存在。
我的问题发生在加载图像,创建顶点之后,然后我需要将它们移动到那里的目标索引,但是它说this.particles.geometry.vertices不存在。
这是我的粒子对象,它包含几何体,几何体内部是一个属性,它是包含我所有顶点的顶点,但我无法按照我显示的方式访问它们。
这是我的完整源代码。 drawImage方法将绘制所有顶点正确,并将顶点对象推入我的几何对象。然后,一旦完成,我将几何体添加到粒子,它工作正常,我将它添加到场景,并显示所有我的顶点。问题是我无法访问我的顶点来操纵它们。所以我的粒子对象,drawImage和包含my循环的render方法就是这一切发生的地方。在我的渲染方法中,它只是说(TS)属性'顶点'在类型'几何|中不存在缓冲几何'。它确实存在,我用图像表明我的粒子对象是一个点对象,它包含我的几何体,并且该几何体内部有一个属性,它的所有顶点都称为顶点。
import { Component, AfterViewInit, ElementRef, Input, ViewChild, HostListener} from '@angular/core';
import { TweenLite } from 'gsap';
import * as THREE from 'three';
declare const require: (moduleId: string) => any;
var OrbitControls = require('three-orbit-controls')(THREE);
@Component({
selector: 'shared-background-scene',
templateUrl: './backgroundScene.component.html',
styleUrls: ['./backgroundScene.component.scss']
})
export class BackgroundSceneComponent {
public scene: THREE.Scene;
private renderer: THREE.WebGLRenderer;
private camera: THREE.PerspectiveCamera;
private cameraTarget: THREE.Vector3;
public controls: THREE.OrbitControls;
public fieldOfView: number = 60;
public nearClippingPane: number = 1;
public farClippingPane: number = 1100;
@ViewChild('canvas')
private canvasRef: ElementRef;
public particles: THREE.Points;
public imageData: any;
public geometry = new THREE.Geometry();
public material = new THREE.PointsMaterial({
size: 3,
color: 0x313742,
sizeAttenuation: false
});
public loadImage() {
//load texture, which is the image, and then get the imagedata, and draw image.
var texture = new THREE.TextureLoader().load("assets/img/example-clouds.png", () => { console.log(texture); this.imageData = this.getImageData(texture.image); this.drawImage(); this.startRendering(); })
}
public getImageData(image: any) {
console.log(image);
// Create canvas for the image
let canvas = document.createElement("canvas");
canvas.width = image.width;
canvas.height = image.width;
// Make sure context is 2d
let context = canvas.getContext("2d");
context!.drawImage(image, 0, 0);
//return the context to be saved to the imageData.
return context!.getImageData(0, 0, image.width, image.height);
}
public drawImage() {
// Create vertices to draw the image.
for (var y = 0, y2 = this.imageData.height; y < y2; y += 2) {
for (var x = 0, x2 = this.imageData.width; x < x2; x += 2) {
if (this.imageData.data[(x * 4 + y * 4 * this.imageData.width) + 3] > 128) {
let vertex:any = new THREE.Vector3();
vertex.x = Math.random() * 1000 - 500;
vertex.y = Math.random() * 1000 - 500;
vertex.z = -Math.random() * 500;
vertex.destination = {
x: x - this.imageData.width / 2,
y: -y + this.imageData.height / 2,
z: 0
};
vertex.speed = Math.random() / 200 + 0.015;
this.geometry.vertices.push(vertex);
}
}
}
console.log(this.geometry);
this.particles = new THREE.Points(this.geometry, this.material);
this.scene.add(this.particles);
console.log(this.particles);
requestAnimationFrame(this.render);
}
constructor() {
this.render = this.render.bind(this);
}
private get canvas(): HTMLCanvasElement {
return this.canvasRef.nativeElement;
}
private createScene() {
this.scene = new THREE.Scene();
}
private createCamera() {
let aspectRatio = this.getAspectRatio();
this.camera = new THREE.PerspectiveCamera(
this.fieldOfView,
aspectRatio,
this.nearClippingPane,
this.farClippingPane
);
// Set position and look at
this.camera.position.x = 10;
this.camera.position.y = 10;
this.camera.position.z = 100;
}
private getAspectRatio(): number {
let height = this.canvas.clientHeight;
if (height === 0) {
return 0;
}
return this.canvas.clientWidth / this.canvas.clientHeight;
}
private startRendering() {
this.renderer = new THREE.WebGLRenderer({
canvas: this.canvas,
antialias: true
});
this.renderer.setPixelRatio(devicePixelRatio);
this.renderer.setSize(this.canvas.clientWidth, this.canvas.clientHeight);
this.renderer.shadowMap.enabled = true;
this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
this.renderer.setClearColor(0xffffff, 1);
this.renderer.autoClear = true;
let component: BackgroundSceneComponent = this;
(function render() {
requestAnimationFrame(render);
component.render();
}());
}
public render() {
this.renderer.render(this.scene, this.camera);
for (var i = 0, j = this.particles.geometry.vertices; i < j; i++) {
var particle = this.particles.geometry.vertices[i];
particle.x += (particle.destination.x - particle.x) * particle.speed;
particle.y += (particle.destination.y - particle.y) * particle.speed;
particle.z += (particle.destination.z - particle.z) * particle.speed;
}
this.particles.geometry.verticesneedupdate = true;
}
public addControls() {
this.controls = new OrbitControls(this.camera);
this.controls.rotateSpeed = 1.0;
this.controls.zoomSpeed = 1.2;
this.controls.addEventListener('change', this.render);
}
private loadCubeModel() {
var geometry = new THREE.BoxGeometry(1, 1, 1);
var material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
var cube = new THREE.Mesh(geometry, material);
this.scene.add(cube);
}
/* Events */
private onResize(event: Event) {
this.canvas.style.width = "100%";
this.canvas.style.height = "100vh";
//console.log("onResize: " + this.canvas.clientWidth + ", " + this.canvas.clientHeight);
this.camera.aspect = this.getAspectRatio();
this.camera.updateProjectionMatrix();
this.renderer.setSize(this.canvas.clientWidth, this.canvas.clientHeight);
this.render();
}
/* LIFECYCLE */
ngAfterViewInit() {
this.createScene();
this.createCamera();
this.loadImage(); // rendering starts here
this.loadCubeModel();
this.addControls();
}
}
使用console.log的快速示例(this.particles.geometry.vertices.length);并获得正确的输出,但它仍然说它不存在。
答案 0 :(得分:1)
原因是,当我们使用THREE.Points
时,TypeScript无法知道我们将它们与Geometry
还是BufferGeometry
一起使用。我只需在您的render()方法中添加以下行:
const geometry = this.particles.geometry as Geometry
,并在以下代码中使用geometry
代替this.particles.geometry
。这实际上将告诉TypeScript“我知道,它将永远是Geometry
,请相信我。”
答案 1 :(得分:0)
我改变了我的公共粒子= THREE.Points; - &GT;公共粒子:any = THREE.Points;
这为我修好了,但我只是没有类型,那很糟糕,但如果你知道你在改变什么,那么你应该没事。
固定代码:
import { Component, AfterViewInit, ElementRef, Input, ViewChild, HostListener} from '@angular/core';
import { TweenLite } from 'gsap';
import * as THREE from 'three';
declare const require: (moduleId: string) => any;
var OrbitControls = require('three-orbit-controls')(THREE);
@Component({
selector: 'shared-background-scene',
templateUrl: './backgroundScene.component.html',
styleUrls: ['./backgroundScene.component.scss']
})
export class BackgroundSceneComponent {
public scene: THREE.Scene;
private renderer: THREE.WebGLRenderer;
private camera: THREE.PerspectiveCamera;
private cameraTarget: THREE.Vector3;
public controls: THREE.OrbitControls;
public fieldOfView: number = 60;
public nearClippingPane: number = 1;
public farClippingPane: number = 1100;
@ViewChild('canvas')
private canvasRef: ElementRef;
public particles:any = THREE.Points;
public imageData: any;
public geometry = new THREE.Geometry();
public material = new THREE.PointsMaterial({
size: 3,
color: 0x313742,
sizeAttenuation: false
});
public loadImage() {
//load texture, which is the image, and then get the imagedata, and draw image.
var texture = new THREE.TextureLoader().load("assets/img/transparentMap.png", () => { console.log(texture); this.imageData = this.getImageData(texture.image); this.drawImage(); this.startRendering(); })
}
public getImageData(image: any) {
console.log(image);
// Create canvas for the image
let canvas = document.createElement("canvas");
canvas.width = image.width;
canvas.height = image.width;
// Make sure context is 2d
let context = canvas.getContext("2d");
context!.drawImage(image, 0, 0);
//return the context to be saved to the imageData.
return context!.getImageData(0, 0, image.width, image.height);
}
public drawImage() {
// Create vertices to draw the image.
for (var y = 0, y2 = this.imageData.height; y < y2; y += 2) {
for (var x = 0, x2 = this.imageData.width; x < x2; x += 2) {
if (this.imageData.data[(x * 4 + y * 4 * this.imageData.width) + 3] > 128) {
let vertex:any = new THREE.Vector3();
vertex.x = Math.random() * 1000 - 500;
vertex.y = Math.random() * 1000 - 500;
vertex.z = -Math.random() * 500;
vertex.destination = {
x: x - this.imageData.width / 2,
y: -y + this.imageData.height / 2,
z: 0
};
vertex.speed = Math.random() / 200 + 0.015;
this.geometry.vertices.push(vertex);
}
}
}
this.particles = new THREE.Points(this.geometry, this.material);
this.scene.add(this.particles);
requestAnimationFrame(this.render);
}
constructor() {
this.render = this.render.bind(this);
}
private get canvas(): HTMLCanvasElement {
return this.canvasRef.nativeElement;
}
private createScene() {
this.scene = new THREE.Scene();
}
private createCamera() {
let aspectRatio = this.getAspectRatio();
this.camera = new THREE.PerspectiveCamera(
this.fieldOfView,
aspectRatio,
this.nearClippingPane,
this.farClippingPane
);
// Set position and look at
this.camera.position.x = 10;
this.camera.position.y = 10;
this.camera.position.z = 100;
}
private getAspectRatio(): number {
let height = this.canvas.clientHeight;
if (height === 0) {
return 0;
}
return this.canvas.clientWidth / this.canvas.clientHeight;
}
private startRendering() {
this.renderer = new THREE.WebGLRenderer({
canvas: this.canvas,
antialias: true
});
this.renderer.setPixelRatio(devicePixelRatio);
this.renderer.setSize(this.canvas.clientWidth, this.canvas.clientHeight);
this.renderer.shadowMap.enabled = true;
this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
this.renderer.setClearColor(0xffffff, 1);
this.renderer.autoClear = true;
let component: BackgroundSceneComponent = this;
(function render() {
requestAnimationFrame(render);
component.render();
}());
}
public render() {
this.renderer.render(this.scene, this.camera);
// Draw image to screen
for (var i = 0, j = this.particles.geometry.vertices.length; i < j; i++) {
var particle:any = this.particles.geometry.vertices[i];
particle.x += (particle.destination.x - particle.x) * particle.speed;
particle.y += (particle.destination.y - particle.y) * particle.speed;
particle.z += (particle.destination.z - particle.z) * particle.speed;
}
this.particles.geometry.verticesNeedUpdate = true;
}
public addControls() {
this.controls = new OrbitControls(this.camera);
this.controls.rotateSpeed = 1.0;
this.controls.zoomSpeed = 1.2;
this.controls.addEventListener('change', this.render);
}
private loadCubeModel() {
var geometry = new THREE.BoxGeometry(1, 1, 1);
var material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
var cube = new THREE.Mesh(geometry, material);
this.scene.add(cube);
}
/* Events */
private onResize(event: Event) {
this.canvas.style.width = "100%";
this.canvas.style.height = "100vh";
//console.log("onResize: " + this.canvas.clientWidth + ", " + this.canvas.clientHeight);
this.camera.aspect = this.getAspectRatio();
this.camera.updateProjectionMatrix();
this.renderer.setSize(this.canvas.clientWidth, this.canvas.clientHeight);
this.render();
}
/* LIFECYCLE */
ngAfterViewInit() {
this.createScene();
this.createCamera();
this.loadImage(); // rendering starts here
this.loadCubeModel();
this.addControls();
}
}