Skip to content

Commit 6094d8d

Browse files
committed
WIP - very basic material editor functionality working
1 parent 7c790f1 commit 6094d8d

File tree

6 files changed

+339
-52
lines changed

6 files changed

+339
-52
lines changed

examples/graphics/node-material.html

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>PlayCanvas Shader Node Material</title>
5+
<meta charset="utf-8">
6+
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
7+
<link rel="icon" type="image/png" href="../playcanvas-favicon.png" />
8+
<script src="../../build/playcanvas.js"></script>
9+
<script src="../../build/playcanvas-extras.js"></script>
10+
<style>
11+
body {
12+
margin: 0;
13+
overflow-y: hidden;
14+
}
15+
</style>
16+
</head>
17+
18+
<body>
19+
<!-- The canvas element -->
20+
<canvas id="application-canvas"></canvas>
21+
<!-- shaders -->
22+
<script id="wobbleVS" type="x-shader/x-vertex">
23+
vec3 wobbleVS(in vec3 wp, in vec3 wn, in float t)
24+
{
25+
return vec3(sin(t*5.0+dot(wp.xy,vec2(1,1)))*0.3)*normalize(wn);
26+
}
27+
</script>
28+
29+
<!-- The script -->
30+
<script>
31+
var entity, light, camera;
32+
var time = 0;
33+
34+
var canvas = document.getElementById("application-canvas");
35+
36+
// Create the application and start the update loop
37+
var app = new pc.Application(canvas);
38+
39+
// Set the canvas to fill the window and automatically change resolution to be the same as the canvas size
40+
app.setCanvasFillMode(pc.FILLMODE_FILL_WINDOW);
41+
app.setCanvasResolution(pc.RESOLUTION_AUTO);
42+
43+
window.addEventListener("resize", function () {
44+
app.resizeCanvas(canvas.width, canvas.height);
45+
});
46+
47+
var miniStats = new pcx.MiniStats(app);
48+
49+
app.scene.ambientLight = new pc.Color(0.2, 0.2, 0.2);
50+
51+
// Create an Entity with a camera component
52+
camera = new pc.Entity();
53+
camera.addComponent("camera", {
54+
clearColor: new pc.Color(0.4, 0.45, 0.5)
55+
});
56+
camera.translate(0, 7, 25);
57+
app.root.addChild(camera);
58+
59+
// Create an entity with a directional light component
60+
var light = new pc.Entity();
61+
light.addComponent("light", {
62+
type: "directional",
63+
color: new pc.Color(1, 0.8, 0.25)
64+
});
65+
app.root.addChild(light);
66+
light.setLocalEulerAngles(85, -100, 0);
67+
68+
var url = "../assets/models/statue.glb";
69+
app.assets.loadFromUrl(url, "container", function (err, asset) {
70+
entity = new pc.Entity();
71+
72+
var modelComponent = entity.addComponent("model", {
73+
type: "asset",
74+
asset: asset.resource.model
75+
});
76+
app.root.addChild(entity);
77+
78+
var model = modelComponent.model;
79+
var diffuseMap = model.getMaterials()[0].diffuseMap;
80+
81+
//start building shader graph
82+
pc.shadergraph.start();
83+
84+
//create a simple PS shader graph - just a 2D texture sample
85+
var texSampleNode = pc.shadergraph.textureSample2D('diffSamp', diffuseMap, pc.shadergraph.uv0);
86+
87+
//hook up PS outputs
88+
pc.shadergraph.connectFragOut(texSampleNode);
89+
90+
//create a custom vertex offset shader graph node
91+
var wobbleVSNode = pc.shadergraph.customNode('wobbleVS', document.getElementById("wobbleVS").textContent);
92+
93+
//hook up custom node inputs
94+
pc.shadergraph.connectCustom(wobbleVSNode, 'wp', pc.shadergraph.worldPosVS);
95+
pc.shadergraph.connectCustom(wobbleVSNode, 'wn', pc.shadergraph.worldNormVS);
96+
pc.shadergraph.connectCustom(wobbleVSNode, 't', pc.shadergraph.param('float', 'uTime', 0.0));
97+
98+
//hook up VS output
99+
pc.shadergraph.connectVertexOffset(wobbleVSNode);
100+
101+
//end graph and assign built graph to material
102+
var material = pc.shadergraph.end();
103+
104+
//assign material to all model meshInstances
105+
model.meshInstances.forEach(function (meshInstance) {
106+
meshInstance.material = material;
107+
});
108+
109+
//initialize shader and update uniforms
110+
material.initShader(app.graphicsDevice);
111+
material.updateUniforms();
112+
113+
//update time parameter every frame
114+
app.on("update", function (dt) {
115+
time += dt;
116+
material.setParameter('IN_uTime_'+material.id, time);
117+
});
118+
119+
app.start();
120+
});
121+
</script>
122+
</body>
123+
</html>

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ var node = {
6161
// VERTEX SHADER BODY
6262
code += begin();
6363

64-
if (options.shaderGraph) {
64+
if (options.shaderGraph && options.shaderGraph.getIoPortByName('OUT_vertOff') ) {
6565
code += rootCallGLSL;
6666
code += " vPosition = getWorldPositionNM()+OUT_vertOff;\n";
6767
code += " gl_Position = matrix_viewProjection*vec4(vPosition,1);\n";
@@ -152,7 +152,7 @@ var node = {
152152
// FRAGMENT SHADER BODY
153153
code += begin();
154154

155-
if (options.shaderGraph) {
155+
if (options.shaderGraph && options.shaderGraph.getIoPortByName('OUT_fragOut') ) {
156156
code += rootCallGLSL;
157157
code += 'gl_FragColor=OUT_fragOut;\n';
158158
}
@@ -175,7 +175,7 @@ var node = {
175175
createShaderDefinition: function (device, options) {
176176
// generate graph
177177
// TODO: support generation of shader variants based on options
178-
var rootDeclGLSL = options.shaderGraph.generateRootDeclGlsl();
178+
var rootDeclGLSL = options.shaderGraph.generateRootDeclGlsl(options.previewPort);
179179
var rootCallGLSL = options.shaderGraph.generateRootCallGlsl();
180180

181181
// GENERATE ATTRIBUTES

src/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ export { Model } from './scene/model.js';
8787
export { Morph } from './scene/morph.js';
8888
export { MorphInstance } from './scene/morph-instance.js';
8989
export { MorphTarget } from './scene/morph-target.js';
90-
export { NodeMaterial } from './scene/materials/node-material.js';
90+
export { NodeMaterial, shadergraph } from './scene/materials/node-material.js';
9191
export { ParticleEmitter } from './scene/particle-system/particle-emitter.js';
9292
export { Picker } from './scene/pick.js';
9393
export { Scene } from './scene/scene.js';

src/resources/material.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ Object.assign(MaterialHandler.prototype, {
5959
if (data.graphData) {
6060
subclass = 'Node';
6161

62-
if (!this._parsers[subclass]) this._parsers[subclass] = new JsonNodeMaterialParser(this._device);
62+
if (!this._parsers[subclass]) this._parsers[subclass] = new JsonNodeMaterialParser();
6363
if (!this._binders[subclass]) this._binders[subclass] = new NodeMaterialBinder(this._assets, this._device, this._parsers[subclass]);
6464
} else {
6565
if (!this._parsers[subclass]) this._parsers[subclass] = new JsonStandardMaterialParser();

src/resources/parser/material/json-node-material.js

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,9 @@ import { NodeMaterial } from '../../../scene/materials/node-material.js';
44
* @class
55
* @name pc.JsonNodeMaterialParser
66
* @description Convert incoming JSON data into a {@link pc.NodeMaterial}.
7-
* @param {pc.GraphicsDevice} device - The graphics device of the application - required for creating placeholder
87
*/
9-
function JsonNodeMaterialParser(device) {
10-
this._device = device;
8+
function JsonNodeMaterialParser() {
119
this._validator = null;
12-
13-
this._placeholderNodeMat = this._genPlaceholderNodeMat();
1410
}
1511

1612
JsonNodeMaterialParser.prototype.parse = function (input) {
@@ -149,8 +145,6 @@ JsonNodeMaterialParser.prototype.initialize = function (material, data) {
149145
if (materialReady) {
150146
material.dirtyShader = true;
151147
material.update();
152-
} else {
153-
material.setPlaceHolderShader(this._placeholderNodeMat);
154148
}
155149
};
156150

@@ -167,14 +161,4 @@ JsonNodeMaterialParser.prototype._validate = function (data) {
167161
return data;
168162
};
169163

170-
JsonNodeMaterialParser.prototype._genPlaceholderNodeMat = function () {
171-
var material = new NodeMaterial('void placeHolder(out vec3 vertOff, out vec4 fragOut){ vertOff=vec3(0); fragOut=vec4(0,0,1,1);}');
172-
173-
// initialize shader and update uniforms
174-
material.initShader(this._device);
175-
material.updateUniforms();
176-
177-
return material;
178-
};
179-
180164
export { JsonNodeMaterialParser };

0 commit comments

Comments
 (0)