Skip to content

Commit 1d2dce0

Browse files
mvaligurskyMartin Valigursky
andauthored
Forward-renderer refactoring - moved shadow related code out (playcanvas#3140)
* Forward-renderer refactoring - moved shadow related code out * changed var to let/const * tiny adjustments to lights engine example * small further refactor * updated lights example - cleaner loading, cookie texture on spotlight * refactor - extracted code to a function * calling renamed function property from lightmapper * typo fix Co-authored-by: Martin Valigursky <mvaligursky@snapchat.com>
1 parent 083528b commit 1d2dce0

File tree

10 files changed

+1016
-944
lines changed

10 files changed

+1016
-944
lines changed

examples/graphics/lights.html

Lines changed: 140 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
<link rel="icon" type="image/png" href="../playcanvas-favicon.png" />
88
<script src="../../build/playcanvas.js"></script>
99
<script src="../../build/playcanvas-extras.js"></script>
10+
<script src="../assets/scripts/asset-loader.js"></script>
1011
<style>
1112
body {
1213
margin: 0;
@@ -20,14 +21,6 @@
2021
<canvas id="application-canvas"></canvas>
2122

2223
<script>
23-
function createMaterial(colors) {
24-
var material = new pc.StandardMaterial();
25-
for (var param in colors) {
26-
material[param] = colors[param];
27-
}
28-
material.update();
29-
return material;
30-
}
3124
</script>
3225

3326
<!-- The script -->
@@ -38,136 +31,157 @@
3831
var app = new pc.Application(canvas, {
3932
keyboard: new pc.Keyboard(window)
4033
});
41-
app.start();
4234

43-
// Set the canvas to fill the window and automatically change resolution to be the same as the canvas size
44-
app.setCanvasFillMode(pc.FILLMODE_FILL_WINDOW);
45-
app.setCanvasResolution(pc.RESOLUTION_AUTO);
46-
47-
window.addEventListener("resize", function () {
48-
app.resizeCanvas(canvas.width, canvas.height);
35+
// A list of assets that need to be loaded
36+
var assetManifest = {
37+
statue: {
38+
type: "container",
39+
url: "../assets/models/statue.glb"
40+
},
41+
font: {
42+
type: "font",
43+
url: "../assets/fonts/arial.json"
44+
},
45+
heart: {
46+
type: "texture",
47+
url: "../assets/textures/heart.png"
48+
},
49+
};
50+
51+
// Load all assets and then run the example
52+
loadManifestAssets(app, assetManifest, function () {
53+
run();
4954
});
5055

51-
var miniStats = new pcx.MiniStats(app);
56+
var spotlight, omnilight, directionallight, statue, text;
5257

53-
app.scene.ambientLight = new pc.Color(0.4, 0.4, 0.4);
58+
function run() {
5459

55-
var entity, light, camera;
60+
app.start();
5661

57-
// Load a model file and create a Entity with a model component
58-
var url = "../assets/models/statue.glb";
59-
app.assets.loadFromUrl(url, "container", function (err, asset) {
60-
entity = new pc.Entity();
61-
entity.addComponent("model", {
62-
type: "asset",
63-
asset: asset.resource.model,
64-
castShadows: true
62+
// Set the canvas to fill the window and automatically change resolution to be the same as the canvas size
63+
app.setCanvasFillMode(pc.FILLMODE_FILL_WINDOW);
64+
app.setCanvasResolution(pc.RESOLUTION_AUTO);
65+
66+
window.addEventListener("resize", function () {
67+
app.resizeCanvas(canvas.width, canvas.height);
6568
});
66-
app.root.addChild(entity);
67-
});
6869

69-
// Create an Entity with a camera component
70-
var camera = new pc.Entity();
71-
camera.addComponent("camera", {
72-
clearColor: new pc.Color(0.4, 0.45, 0.5)
73-
});
74-
camera.translate(0, 7, 24);
75-
camera.rotate(0, 0, 0);
76-
app.root.addChild(camera);
77-
78-
// Create an Entity for the ground
79-
var ground = new pc.Entity();
80-
ground.addComponent("model", {
81-
type: "box"
82-
});
83-
ground.setLocalScale(50, 1, 50);
84-
ground.setLocalPosition(0, -0.5, 0);
70+
var miniStats = new pcx.MiniStats(app);
8571

86-
var material = createMaterial({
87-
ambient: pc.Color.GRAY,
88-
diffuse: pc.Color.GRAY
89-
});
90-
ground.model.material = material;
91-
app.root.addChild(ground);
92-
93-
// Create an spot light
94-
var spotlight = new pc.Entity();
95-
spotlight.addComponent("light", {
96-
type: "spot",
97-
color: pc.Color.WHITE,
98-
outerConeAngle: 60,
99-
innerConeAngle: 40,
100-
range: 100,
101-
intensity: 0.6,
102-
castShadows: true,
103-
shadowBias: 0.005,
104-
normalOffsetBias: 0.01,
105-
shadowResolution: 2048
106-
});
72+
app.scene.ambientLight = new pc.Color(0.4, 0.4, 0.4);
10773

108-
var cone = new pc.Entity();
109-
cone.addComponent("model", {
110-
type: "cone"
111-
});
112-
cone.model.material = createMaterial({ emissive: pc.Color.WHITE });
113-
spotlight.addChild(cone);
114-
app.root.addChild(spotlight);
115-
116-
// Create a omni light
117-
var omnilight = new pc.Entity();
118-
omnilight.addComponent("light", {
119-
type: "omni",
120-
color: pc.Color.YELLOW,
121-
range: 100,
122-
castShadows: true,
123-
intensity: 0.6
124-
});
125-
omnilight.addComponent("model", {
126-
type: "sphere"
127-
});
128-
omnilight.model.material = createMaterial({ diffuse: new pc.Color(0, 0, 0), emissive: pc.Color.YELLOW });
129-
app.root.addChild(omnilight);
130-
131-
// Create a directional light
132-
var directionallight = new pc.Entity();
133-
directionallight.addComponent("light", {
134-
type: "directional",
135-
color: pc.Color.CYAN,
136-
range: 100,
137-
castShadows: true,
138-
shadowBias: 0.05,
139-
normalOffsetBias: 0.1,
140-
intensity: 0.6
141-
});
142-
app.root.addChild(directionallight);
74+
// add an instance of the statue to the hierarchy
75+
statue = assetManifest["statue"].asset.resource.instantiateRenderEntity({
76+
castShadows: true
77+
});
78+
app.root.addChild(statue);
79+
80+
function createMaterial(colors) {
81+
var material = new pc.StandardMaterial();
82+
for (var param in colors) {
83+
material[param] = colors[param];
84+
}
85+
material.update();
86+
return material;
87+
}
14388

89+
// Create an Entity with a camera component
90+
var camera = new pc.Entity();
91+
camera.addComponent("camera", {
92+
clearColor: new pc.Color(0.4, 0.45, 0.5)
93+
});
94+
camera.translate(0, 12, 45);
95+
camera.rotate(-10, 0, 0);
96+
app.root.addChild(camera);
97+
98+
// Create an Entity for the ground
99+
var ground = new pc.Entity();
100+
ground.addComponent("model", {
101+
type: "box"
102+
});
103+
ground.setLocalScale(50, 1, 50);
104+
ground.setLocalPosition(0, -0.5, 0);
144105

145-
// Create a 2D screen for text rendering
146-
var screen = new pc.Entity();
147-
screen.addComponent("screen", {
148-
referenceResolution: new pc.Vec2(1280, 720),
149-
scaleBlend: 0.5,
150-
scaleMode: pc.SCALEMODE_BLEND,
151-
screenSpace: true
152-
});
153-
app.root.addChild(screen);
106+
var material = createMaterial({
107+
ambient: pc.Color.GRAY,
108+
diffuse: pc.Color.GRAY
109+
});
110+
ground.model.material = material;
111+
app.root.addChild(ground);
112+
113+
// Create an spot light
114+
spotlight = new pc.Entity();
115+
spotlight.addComponent("light", {
116+
type: "spot",
117+
color: pc.Color.WHITE,
118+
outerConeAngle: 25,
119+
innerConeAngle: 20,
120+
range: 100,
121+
intensity: 0.6,
122+
castShadows: true,
123+
shadowBias: 0.005,
124+
normalOffsetBias: 0.01,
125+
shadowResolution: 2048,
126+
127+
// heart texture's alpha channel as a cookie texture
128+
cookie: assetManifest["heart"].asset.resource,
129+
cookieChannel: "a"
130+
});
131+
132+
var cone = new pc.Entity();
133+
cone.addComponent("model", {
134+
type: "cone"
135+
});
136+
cone.model.material = createMaterial({ emissive: pc.Color.WHITE });
137+
spotlight.addChild(cone);
138+
app.root.addChild(spotlight);
139+
140+
// Create a omni light
141+
omnilight = new pc.Entity();
142+
omnilight.addComponent("light", {
143+
type: "omni",
144+
color: pc.Color.YELLOW,
145+
range: 100,
146+
castShadows: true,
147+
intensity: 0.6
148+
});
149+
omnilight.addComponent("model", {
150+
type: "sphere"
151+
});
152+
omnilight.model.material = createMaterial({ diffuse: new pc.Color(0, 0, 0), emissive: pc.Color.YELLOW });
153+
app.root.addChild(omnilight);
154+
155+
// Create a directional light
156+
directionallight = new pc.Entity();
157+
directionallight.addComponent("light", {
158+
type: "directional",
159+
color: pc.Color.CYAN,
160+
range: 100,
161+
castShadows: true,
162+
shadowDistance: 100,
163+
shadowBias: 0.2,
164+
normalOffsetBias: 0.1,
165+
intensity: 0.6
166+
});
167+
app.root.addChild(directionallight);
154168

155-
// Load a font
156-
var fontAsset = new pc.Asset('arial.json', "font", {
157-
url: "../assets/fonts/arial.json"
158-
});
159-
fontAsset.on('load', onFontLoaded);
160-
app.assets.add(fontAsset);
161-
app.assets.load(fontAsset);
162169

163-
// When the font is loaded, create text to show which lights are enabled
164-
var text;
165-
function onFontLoaded() {
170+
// Create a 2D screen for text rendering
171+
var screen = new pc.Entity();
172+
screen.addComponent("screen", {
173+
referenceResolution: new pc.Vec2(1280, 720),
174+
scaleBlend: 0.5,
175+
scaleMode: pc.SCALEMODE_BLEND,
176+
screenSpace: true
177+
});
178+
app.root.addChild(screen);
179+
166180
// Create a basic text element
167181
text = new pc.Entity();
168182
text.addComponent("element", {
169183
anchor: new pc.Vec4(0.1, 0.1, 0.5, 0.5),
170-
fontAsset: fontAsset,
184+
fontAsset: assetManifest["font"].asset,
171185
fontSize: 28,
172186
pivot: new pc.Vec2(0.5, 0.1),
173187
type: pc.ELEMENTTYPE_TEXT,
@@ -195,19 +209,18 @@
195209
var angleRad = 0;
196210
app.on("update", function (dt) {
197211
angleRad += 0.3 * dt;
198-
if (entity) {
199212

200-
spotlight.lookAt(entity.getPosition());
213+
if (statue) {
214+
215+
spotlight.lookAt(statue.getPosition());
201216
spotlight.rotateLocal(90, 0, 0);
202-
spotlight.setLocalPosition(20 * Math.sin(angleRad), 5, 20 * Math.cos(angleRad));
217+
spotlight.setLocalPosition(20 * Math.sin(angleRad * 0.5), 25, 20 * Math.cos(angleRad * 0.5));
203218

204-
omnilight.setLocalPosition(5 * Math.sin(-2 * angleRad), 10, 5 * Math.cos(-2 * angleRad));
219+
omnilight.setLocalPosition(5 * Math.sin(-2 * angleRad), 15, 5 * Math.cos(-2 * angleRad));
205220

206221
directionallight.setLocalEulerAngles(45, 60 * angleRad, 0);
207-
}
208222

209-
// update text showing which lights are enabled
210-
if (text) {
223+
// update text showing which lights are enabled
211224
text.element.text =
212225
"[Key 1] Omni light: " + omnilight.enabled +
213226
"\n[Key 2] Spot light: " + spotlight.enabled +

src/deprecated.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ import { calculateTangents, createBox, createCapsule, createCone, createCylinder
5555
import { partitionSkin } from './scene/skin-partition.js';
5656
import { BasicMaterial } from './scene/materials/basic-material.js';
5757
import { DepthMaterial } from './scene/materials/depth-material.js';
58-
import { ForwardRenderer } from './scene/forward-renderer.js';
58+
import { ForwardRenderer } from './scene/renderer/forward-renderer.js';
5959
import { GraphNode } from './scene/graph-node.js';
6060
import { Material } from './scene/materials/material.js';
6161
import { Mesh } from './scene/mesh.js';

src/framework/application.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import {
2323
SORTMODE_NONE, SORTMODE_MANUAL
2424
} from '../scene/constants.js';
2525
import { BatchManager } from '../scene/batching/batch-manager.js';
26-
import { ForwardRenderer } from '../scene/forward-renderer.js';
26+
import { ForwardRenderer } from '../scene/renderer/forward-renderer.js';
2727
import { ImmediateData } from '../scene/immediate.js';
2828
import { Layer } from '../scene/layer.js';
2929
import { LayerComposition } from '../scene/layer-composition.js';

src/graphics/program-lib/programs/standard.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
} from '../../../scene/constants.js';
2424
import { WorldClusters } from '../../../scene/world-clusters.js';
2525
import { LayerComposition } from '../../../scene/layer-composition.js';
26+
import { ShadowMapManager } from '../../../scene/renderer/shadow-map-manager.js';
2627

2728
import { begin, end, fogCode, gammaCode, precisionCode, skinCode, tonemapCode, versionCode } from './common.js';
2829

@@ -895,8 +896,8 @@ var standard = {
895896

896897
} else if (shadowPass) {
897898
// ##### SHADOW PASS #####
898-
var smode = options.pass - SHADER_SHADOW;
899-
var numShadowModes = 5;
899+
const smode = options.pass - SHADER_SHADOW;
900+
const numShadowModes = ShadowMapManager.numShadowModes;
900901
lightType = Math.floor(smode / numShadowModes);
901902
var shadowType = smode - lightType * numShadowModes;
902903

src/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ export { BatchManager } from './scene/batching/batch-manager.js';
8383
export { Camera } from './scene/camera.js';
8484
export { WorldClusters } from './scene/world-clusters.js';
8585
export { DepthMaterial } from './scene/materials/depth-material.js';
86-
export { ForwardRenderer } from './scene/forward-renderer.js';
86+
export { ForwardRenderer } from './scene/renderer/forward-renderer.js';
8787
export { GraphNode } from './scene/graph-node.js';
8888
export { Layer } from './scene/layer.js';
8989
export { LayerComposition } from './scene/layer-composition.js';

0 commit comments

Comments
 (0)