-
Notifications
You must be signed in to change notification settings - Fork 1.3k
/
cubemap-renderer.js
127 lines (106 loc) · 4.46 KB
/
cubemap-renderer.js
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
// How to use in the Editor:
// - create entity with Camera component - position of the entity defines where the cubemap is rendered from
// and properties of the Camera are used to render cubemap (adjust near / far distance, clearing, layers and other properties)
// Note: the layers should contain all layers visible by cubemap camera.
// - to use generated cube map, you can access it like this using script:
// material.cubeMap = entity.script.cubemapRenderer.cubeMap;
var CubemapRenderer = pc.createScript('cubemapRenderer');
CubemapRenderer.attributes.add('resolution', {
title: 'Resolution',
description: 'Resolution of one side of a cubemap. Use power of 2 resolution if you wish to use Mipmaps.',
type: 'number',
default: 64
});
CubemapRenderer.attributes.add('mipmaps', {
title: 'Mipmaps',
description: 'If set to true, mipmaps will be allocated and autogenerated.',
type: 'boolean',
default: true
});
CubemapRenderer.attributes.add('depth', {
title: 'Depth',
description: 'If set to true, depth buffer will be created.',
type: 'boolean',
default: true
});
// initialize code called once per entity
CubemapRenderer.prototype.initialize = function () {
// this entity needs to have camera component as well
var camera = this.entity.camera;
if (!camera) {
console.error("CubemapRenderer component requires Camera component to be created on the Entity.");
return;
}
// disable camera component, as it's used only as a source of properties
camera.enabled = false;
// limit maximum texture size
var resolution = Math.min(this.resolution, this.app.graphicsDevice.maxCubeMapSize);
// Create cubemap render target with specified resolution and mipmap generation
this.cubeMap = new pc.Texture(this.app.graphicsDevice, {
name: this.entity.name + ':CubemapRenderer-' + resolution,
width: resolution,
height: resolution,
format: pc.PIXELFORMAT_RGBA8,
cubemap: true,
mipmaps: this.mipmaps,
minFilter: pc.FILTER_LINEAR_MIPMAP_LINEAR,
magFilter: pc.FILTER_LINEAR
});
// angles to render camera for all 6 faces
var cameraRotations = [
new pc.Quat().setFromEulerAngles(0, 90, 0),
new pc.Quat().setFromEulerAngles(0, -90, 0),
new pc.Quat().setFromEulerAngles(-90, 0, 180),
new pc.Quat().setFromEulerAngles(90, 0, 180),
new pc.Quat().setFromEulerAngles(0, 180, 0),
new pc.Quat().setFromEulerAngles(0, 0, 0)
];
// set up rendering for all 6 faces
for (var i = 0; i < 6; i++) {
// render target, connected to cubemap texture face
var renderTarget = new pc.RenderTarget({
name: 'CubemapRenderer-Face' + i,
colorBuffer: this.cubeMap,
depth: this.depth,
face: i,
flipY: !this.app.graphicsDevice.isWebGPU
});
// create a child entity with the camera for this face
var e = new pc.Entity("CubeMapCamera_" + i);
e.addComponent('camera', {
aspectRatio: 1,
fov: 90,
// cubemap will render all layers as setup on Entity's camera
layers: camera.layers,
// priority
priority: camera.priority,
// copy other camera properties
clearColor: camera.clearColor,
clearColorBuffer: camera.clearColorBuffer,
clearDepthBuffer: camera.clearDepthBuffer,
clearStencilBuffer: camera.clearStencilBuffer,
farClip: camera.farClip,
nearClip: camera.nearClip,
frustumCulling: camera.frustumCulling,
// this camera renders into texture target
renderTarget: renderTarget
});
// add the camera as a child entity
this.entity.addChild(e);
// set up its rotation
e.setRotation(cameraRotations[i]);
// Before the first camera renders, trigger onCubemapPreRender event on the entity.
if (i === 0) {
e.camera.onPreRender = () => {
this.entity.fire('onCubemapPreRender');
};
}
// When last camera is finished rendering, trigger onCubemapPostRender event on the entity.
// This can be listened to by the user, and the resulting cubemap can be further processed (e.g prefiltered)
if (i === 5) {
e.camera.onPostRender = () => {
this.entity.fire('onCubemapPostRender');
};
}
}
};