-
Notifications
You must be signed in to change notification settings - Fork 5
/
MeshRendererComponent.ts
153 lines (142 loc) · 5.69 KB
/
MeshRendererComponent.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
import grimoirejs from "grimoirejs";
import GLM from "grimoirejs-math/ref/GLM";
import Component from "grimoirejs/ref/Node/Component";
import GomlNode from "grimoirejs/ref/Node/GomlNode";
import IAttributeDeclaration from "grimoirejs/ref/Node/IAttributeDeclaration";
import Geometry from "../Geometry/Geometry";
import IMaterialArgument from "../Material/IMaterialArgument";
import IRenderable from "../SceneRenderer/IRenderable";
import IRenderArgument from "../SceneRenderer/IRenderArgument";
import CameraComponent from "./CameraComponent";
import MaterialContainerComponent from "./MaterialContainerComponent";
import SceneComponent from "./SceneComponent";
import TransformComponent from "./TransformComponent";
const { vec3 } = GLM;
/**
* シーン中に存在するメッシュ一つあたりのレンダリングを司るコンポーネント
* このメッシュが、対象となるノードの`Transform`や描画に用いる`Camera`、マテリアルなどを考慮して実際のレンダリングを行います。
*/
export default class MeshRenderer extends Component implements IRenderable {
/**
* Find scene tag recursively.
* @param {GomlNode} node [the node to searching currently]
* @return {SceneComponent} [the scene component found]
*/
private static _findContainedScene(node: GomlNode): SceneComponent {
if (node.parent) {
const scene = node.parent.getComponent(SceneComponent);
if (scene) {
return scene;
} else {
return MeshRenderer._findContainedScene(node.parent);
}
} else {
return null;
}
}
public static attributes: { [key: string]: IAttributeDeclaration } = {
/**
* 描画に用いる形状データ
*/
geometry: {
converter: "Geometry",
default: "quad",
},
/**
* 描画に用いるインデックスバッファ名
*/
indexGroup: {
converter: "String",
default: "default",
},
/**
* このメッシュが属するレイヤー
*
* 詳しくは`render-scene`ノードを参考にしてください。
*/
layer: {
converter: "String",
default: "default",
},
/**
* 描画するインデックスの個数
*
* デフォルトの状態でジオメトリの全インデックスを描画する
*/
drawCount: {
converter: "Number",
default: Number.MAX_VALUE,
},
/**
* 描画するジオメトリのインデックスのオフセット
*/
drawOffset: {
converter: "Number",
default: 0,
},
};
public index: number;
public renderArgs: { [key: string]: any } = {};
public geometry: Promise<Geometry>;
public geometryInstance: Geometry;
private indexGroup: string;
private layer: string;
private drawOffset: number;
private drawCount: number;
private _materialContainer: MaterialContainerComponent;
private _transformComponent: TransformComponent;
private _containedScene: SceneComponent;
private _priortyCalcCache = new Float32Array(3);
public getRenderingPriorty(camera: CameraComponent, technique: string): number {
if (!this.geometryInstance || !this._materialContainer.material.techniques[technique]) {
return Number.NEGATIVE_INFINITY;
}
vec3.add(this._priortyCalcCache, camera.transform.globalPosition.rawElements, this.geometryInstance.aabb.Center.rawElements);
vec3.sub(this._priortyCalcCache, this._priortyCalcCache, this._transformComponent.globalPosition.rawElements);
return this._materialContainer.getDrawPriorty(vec3.sqrLen(this._priortyCalcCache), technique); // Obtains distance between camera and center of aabb
}
public $awake(): void {
this.__bindAttributes();
this.getAttributeRaw("geometry").watch(async() => {
this.geometryInstance = await this.geometry;
}, true);
}
public $mount(): void {
this._transformComponent = this.node.getComponent(TransformComponent);
this._materialContainer = this.node.getComponent(MaterialContainerComponent);
this._containedScene = MeshRenderer._findContainedScene(this.node);
this._containedScene.queueRegistory.addRenderable(this);
}
public $unmount(): void {
this._containedScene.queueRegistory.removeRenderable(this);
}
public render(args: IRenderArgument): void {
if (!this.node.isActive || !this.enabled || this.layer !== args.layer) {
return;
}
if (!this.geometryInstance || (!args.material && !this._materialContainer.material)) {
return; // material is not instanciated yet.
}
const renderArgs = {
indexGroup: this.indexGroup,
geometry: this.geometryInstance,
camera: args.camera,
transform: this._transformComponent,
viewport: args.viewport,
drawCount: this.drawCount,
drawOffset: this.drawOffset,
sceneDescription: args.sceneDescription,
rendererDescription: args.rendererDescription,
technique: args.technique,
renderable: this,
} as IMaterialArgument;
if (grimoirejs.debug && window["spector"]) {
window["spector"].setMarker(`Mesh renderer:${this.node.id}`);
}
this._materialContainer.material.draw(renderArgs);
this.node.emit("render", args);
}
public setRenderableIndex(index: number): void {
this.index = index;
}
}