// Load multiple ShaderFrog shaders
58 | runtime.load([
59 | 'Copy_of_Gems.json',
60 | 'Water_or_Oil.json'
61 | ], function( shaders ) {
62 |
63 | // `shaders` will be an array with the material data in the same order you
64 | // specified when calling `load
65 |
66 | // Get the Three.js material you can assign to your objects
67 | // ShaderFrog shader 1 (reflection effect)
68 | var materialTop = runtime.get( shaders[ 0 ].name );
69 |
70 | // You set uniforms the same way as a regular THREE.js shader. In this
71 | // case, the shader uses a cube camera for reflection, so we have to set
72 | // its value to the renderTarget of a cubeCamera we create
73 | materialTop.uniforms.reflectionSampler.value = cubeCamera.renderTarget;
74 | meshTop.material = materialTop;
75 |
76 | // ShaderFrog shader 2 (oily effect)
77 | var materialBottom = runtime.get( shaders[ 1 ].name );
78 | meshBottom.material = materialBottom;
79 | });
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/example/example.js:
--------------------------------------------------------------------------------
1 | var runtime = new ShaderFrogRuntime(),
2 | width = 800, height = 600,
3 | clock = new THREE.Clock(),
4 | camera, cubeCamera, scene, renderer, meshTop, meshBottom, cubeCamera, leftSphere, rightSphere;
5 |
6 | // Load multiple ShaderFrog shaders
7 | runtime.load([
8 | 'http://andrewray.me/stuff/Reflection_Cube_Map.json',
9 | 'https://s3-us-west-1.amazonaws.com/shader-frog/example/Water_or_Oil.json'
10 | ], function( shaders ) {
11 |
12 | // `shaders` will be an array with the material data in the same order you
13 | // specified when calling `load
14 |
15 | // Get the Three.js material you can assign to your objects
16 | // ShaderFrog shader 1 (reflection effect)
17 | var materialTop = runtime.get( shaders[ 0 ].name );
18 |
19 | // You set uniforms the same way as a regular THREE.js shader. In this
20 | // case, the shader uses a cube camera for reflection, so we have to set
21 | // its value to the renderTarget of a cubeCamera we create
22 | THREE.ImageUtils.crossOrigin = '';
23 | var urls = [ 'posx', 'negx', 'posy', 'negy', 'posz', 'negz' ].map( ( url ) => {
24 | return 'https://s3-us-west-1.amazonaws.com/shader-frog/' + url + '_lanc_chapel.jpg';
25 | });
26 | materialTop.uniforms.iChannel0.value = THREE.ImageUtils.loadTextureCube( urls );
27 | meshTop.material = materialTop;
28 |
29 | // ShaderFrog shader 2 (oily effect)
30 | var materialBottom = runtime.get( shaders[ 1 ].name );
31 | meshBottom.material = materialBottom;
32 | });
33 |
34 | init();
35 | animate();
36 |
37 | function init() {
38 |
39 | scene = new THREE.Scene();
40 |
41 | // Cameras
42 | camera = new THREE.PerspectiveCamera( 50, width / height, 1, 10000 );
43 | camera.position.z = 100;
44 | scene.add( camera );
45 | runtime.registerCamera( camera );
46 |
47 | cubeCamera = new THREE.CubeCamera( 0.1, 10000, 128 );
48 | scene.add( cubeCamera );
49 |
50 | // Main object
51 | var topGeometry = new THREE.SphereGeometry( 20, 10, 10 );
52 | meshTop = new THREE.Mesh( topGeometry );
53 | meshTop.position.y = 20;
54 | scene.add( meshTop );
55 |
56 | // Second main object
57 | var bottomGeometry = new THREE.SphereGeometry( 20, 10, 10 );
58 | meshBottom = new THREE.Mesh( bottomGeometry );
59 | meshBottom.position.y = -20;
60 | scene.add( meshBottom );
61 |
62 | // Decorative objects
63 | var other = new THREE.SphereGeometry( 10, 20, 50, 50 );
64 | leftSphere = new THREE.Mesh(other, new THREE.MeshBasicMaterial({
65 | color: 0xff0000
66 | }));
67 | leftSphere.position.x -= 45;
68 | scene.add(leftSphere);
69 |
70 | var cyl = new THREE.CylinderGeometry( 1, 1, 100, 5 );
71 | var cylMesh = new THREE.Mesh(cyl, new THREE.MeshBasicMaterial({
72 | color: 0x0044ff
73 | }));
74 | cylMesh.position.x += 45;
75 | scene.add(cylMesh);
76 |
77 | var cyl2 = new THREE.CylinderGeometry( 1, 1, 100, 5 );
78 | var cylMesh2 = new THREE.Mesh(cyl2, new THREE.MeshBasicMaterial({
79 | color: 0x0044ff
80 | }));
81 | cylMesh2.position.x -= 45;
82 | scene.add(cylMesh2);
83 |
84 | var other2 = new THREE.SphereGeometry( 10, 20, 50, 50 );
85 | rightSphere = new THREE.Mesh(other2, new THREE.MeshBasicMaterial({
86 | color: 0x00ff00
87 | }));
88 | rightSphere.position.x += 45;
89 | scene.add(rightSphere);
90 |
91 | renderer = new THREE.WebGLRenderer();
92 | renderer.setSize( width, height );
93 |
94 | document.getElementById( 'canvas' ).appendChild( renderer.domElement );
95 |
96 | }
97 |
98 | function animate() {
99 |
100 | requestAnimationFrame( animate );
101 | render();
102 |
103 | }
104 |
105 | function render() {
106 |
107 | meshTop.rotation.x += 0.01;
108 | meshTop.rotation.y += 0.02;
109 |
110 | var time = clock.getElapsedTime();
111 |
112 | runtime.updateShaders( time );
113 |
114 | leftSphere.position.y = 40 * Math.sin( new Date() * 0.001 );
115 | rightSphere.position.y = -40 * Math.sin( new Date() * 0.001 );
116 |
117 | meshTop.visible = false;
118 | cubeCamera.updateCubeMap( renderer, scene );
119 | meshTop.visible = true;
120 |
121 | renderer.render( scene, camera );
122 |
123 | }
124 |
--------------------------------------------------------------------------------
/THREE_SHADER_FORMAT.md:
--------------------------------------------------------------------------------
1 | # Problem
2 |
3 | THREE.js does not have a defined shader format for sharing raw GLSL shader code to load into a [`RawShaderMaterial`](http://threejs.org/docs/#Reference/Materials/RawShaderMaterial). This format is also what is currently used by the [ShaderFrog](http://shaderfrog.com) runtime, found in this repository. [ShaderFrog](http://shaderfrog.com) requires a format to make shaders portable to the end user. This document suggests such a format.
4 |
5 | This proposed format has some main pragmatic goals:
6 | - Provide a way to identify a shader when used in the end user's application;
7 | - Document the uniforms and their types used in the shader. This prevents the end user needing to duplicate uniform types in their implementation of the shader. For example, a user having to type `material.uniforms.color = { type: 'c' }` is redundant, since [ShaderFrog](http://shaderfrog.com) already knows that the `color` uniform is a [`THREE.Color`](http://threejs.org/docs/#Reference/Math/Color).
8 |
9 | # Proposed Format
10 |
11 | An incomplete example can be found at [Reflection_Cube_Map.json](https://github.com/AndrewRayCode/ShaderFrog-Runtime/blob/master/example/Reflection_Cube_Map.json). The format is described with comments below.
12 |
13 | The suggested format is a valid JSON file. It contains no executable Javascript as is not loaded via JSONP. Example data is included with each key as well as if the key is required or not.
14 |
15 | #### Identifier
16 |
17 | (optional int) "id": 84,
18 | (required string) "name": "Reflection Cube Map",
19 |
20 | At runtime, [ShaderFrog](http://shaderfrog.com) needs a way to identifier shaders. The `id` is provided for convenience in case the user has to load different shaders that have the same name (unlikely).
21 |
22 | #### Raw GLSL code
23 |
24 | (required string) "fragment": "precision highp float;\n...",
25 | (required string) "vertex": "precision highp float;\n...",
26 |
27 | Three.js [`RawShaderMaterial`](http://threejs.org/docs/#Reference/Materials/RawShaderMaterial) does not have a default fragment nor vertex program, so both programs are required.
28 |
29 | #### Uniforms
30 |
31 | Uniforms are stored as a dictionary with the uniform name as the key.
32 |
33 | "uniforms": { ... }
34 |
35 | An example uniform:
36 |
37 | "cameraPosition": {
38 | (required string) "type": "v3",
39 | (required any) "value": serialized default value,
40 | (optional string) "glslType": "vec3",
41 | (optional string) "name": "cameraPosition",
42 | (optional string) "description": "A description"
43 | },
44 |
45 | Both the `type` and the `glslType` are known to [ShaderFrog](http://shaderfrog.com) when editing the shader. Three.js requires passing `glslType` in the [`RawShaderMaterial`](http://threejs.org/docs/#Reference/Materials/RawShaderMaterial) uniform, as in `material.uniforms.num = { type: 'f', value: 0 };`
46 |
47 | The `type` is provided as a convenience, and is specific to Three.js. For example, in a shader, a `vec3` is always a `vec3`. In Three.js you can pass in either a [Three.Color](http://threejs.org/docs/#Reference/Math/Color) or a [Three.Vector3](http://threejs.org/docs/#Reference/Math/Vector3). In the user's application, this matters because if you need to manipulate the uniform at runtime, colors and vector3s have different convenience methods for manipulation.
48 |
49 | #### Uniform Value
50 |
51 | Shaders should ship with default values to minimize the amount of code the user has to write. Coming from [ShaderFrog](http://shaderfrog.com), default values exist for every uniform. **This requires serialization of Three.js types**. Below is an incomplete list of mappings to Three.js types.
52 |
53 | **vec3 (THREE.Color)**
54 |
55 | "value": {
56 | "r": 1,
57 | "g": 1,
58 | "b": 1
59 | },
60 |
61 | **vec2 (THREE.Vector2)**
62 |
63 | "value": {
64 | "x": 0,
65 | "y": 0
66 | },
67 |
68 | **vec3 (THREE.Vector3)**
69 |
70 | "value": {
71 | "x": 0,
72 | "y": 0,
73 | "z": 0
74 | },
75 |
76 | **vec4 (THREE.Vector4)**
77 |
78 | "value": {
79 | "x": 0,
80 | "y": 0,
81 | "z": 0,
82 | "w": 0
83 | },
84 |
85 | **samplerCube (Three.TextureCube)** often used for reflection shaders (incomplete)
86 |
87 | "value": {
88 | "image": "nissi_beach.jpg",
89 | "name": "Nissi Beach",
90 | "description": "Nissi Beach",
91 | "isSamplerCube": true
92 | },
93 |
94 | **samplerCube (Three.CubeCamera)** for real-time reflections
95 |
96 | "value": {
97 | "isCubeCamera": true
98 | },
99 |
100 | **sampler2D (Three.Texture)**
101 |
102 | "value": {
103 | "image": "http://full-path-to-img.extension",
104 | },
105 |
106 | **mat3, mat4**
107 |
108 | TODO
109 |
110 | The following use literals in JSON to represent their values:
111 |
112 | - float (Number)
113 | - int (Number)
114 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | **Please file [ShaderFrog.com](http://shaderfrog.com) bugs here!**
4 |
5 | # Deprecation Notice: State of ShaderFrog
6 |
7 | The current ShaderFrog site and engine is in maintenence mode only. The core
8 | engine and compiler are buggy and I haven't actively developed on the current
9 | version of ShaderFrog in several years now. Due to buggy and fundamentally
10 | flawed core nature of ShaderFrog, I'm no longer actively working on it. I
11 | apologize for any frustration the bugs or lack of support have caused to your
12 | development process.
13 |
14 | Instead, I'm working on a new version of the algorithm, Shaderfrog 2.0, starting with a
15 | ground up build of a [GLSL compiler](https://www.npmjs.com/package/@shaderfrog/glsl-parser). I post updates when I have them [as @andrewray on Twitter](https://twitter.com/andrewray)
16 | if you want to follow along. There is no ETA on a new launch date. As of October
17 | 2021, I've made significant progress on ShaderFrog 2.0, and I hope to keep
18 | posting regular updates and share demos as soon as I have them.
19 |
20 | # ShaderFrog Runtime Library
21 |
22 | This is a utility library to load and update [ShaderFrog.com](http://shaderfrog.com) shaders into your THREE.js scene or application.
23 |
24 | ## Demo
25 |
26 | [**Online Demo**](http://shaderfrog.com/runtime/index.html)
27 |
28 | Demo source found in the [example/](https://github.com/AndrewRayCode/ShaderFrog-Runtime/tree/master/example) folder.
29 |
30 | ## Usage
31 |
32 | ### npm
33 |
34 | npm install --save shaderfrog-runtime
35 |
36 | var ShaderFrogRuntime = require( 'shaderfrog-runtime' ):
37 |
38 | ### Vanilla JavaScript
39 |
40 | Download the [built Javascript file](http://shaderfrog.com/runtime/shaderfrog-runtime.min.js) and include it in your project *after* THREE.js:
41 |
42 |
43 |
44 | ### Instantiation
45 |
46 | Instantiate a new runtime:
47 |
48 | var runtime = new ShaderFrogRuntime();
49 |
50 | Instantiate a new clock:
51 |
52 | var clock = new THREE.Clock();
53 |
54 | Load your desired shader, and assign it to a material:
55 |
56 | runtime.load( 'Your_Shader.json', function( shaderData ) {
57 |
58 | // Get the Three.js material you can assign to your objects
59 | var material = runtime.get( shaderData.name );
60 |
61 | // Assign it to your objects
62 | mesh.material = material;
63 | });
64 |
65 | In your initialization code, register the main camera, which is the one that you call `renderer.render( scene, camera )` with:
66 |
67 | runtime.registerCamera( camera );
68 |
69 | This tells the ShaderFrog runtime how to update the `cameraPosition` uniform, which some shaders use to calculate things based on the camera, like reflection.
70 |
71 | In your animation loop, update the running shaders that the ShaderFrog runtime knows about:
72 |
73 | runtime.updateShaders( clock.getElapsedTime() );
74 |
75 | A full example can be found in the [example/](https://github.com/AndrewRayCode/ShaderFrog-Runtime/tree/master/example) folder.
76 |
77 | ## API
78 |
79 | **Warning:** This API is volatile and subject to change in future versions.
80 |
81 | #### `runtime.registerCamera( THREE.Camera camera )`
82 |
83 | Tells the runtime to use this camera's position for the default `cameraPosition` uniform. This uniform is normally passed by default in THREE.js to shader materials, but ShaderFrog shaders use the RawSahderMaterial class.
84 |
85 | #### `runtime.updateShaders( Float time )`
86 |
87 | Update uniform values for shaders, specifically `float time`, `vec3 cameraPosition`, and `mat4 viewMatrix`. The only uniform the runtime cannot define is `time` which should be provided by the elapsed time in milliseconds. [THREE.Clock.getElapsedTime()](http://threejs.org/docs/#Reference/Core/Clock) provies this value.
88 |
89 | #### `runtime.load( [ String source | Array sources ], Function callback )`
90 |
91 | Call this function with either:
92 |
93 | runtime.load( 'material.json', function( material ) ) {
94 | var shader = runtime.get( material.name ); ...
95 | }
96 |
97 | ...for one material, or...
98 |
99 | runtime.load( [ 'material1.json', 'material2.json' ], function( materials ) ) {
100 | var shader = runtime.get( materials[ 0 ].name ); ...
101 | }
102 |
103 | Load the specified URLs and parse them into materials. If you pass in an array of URLs, the callback receives an array of materials in the same order you specified.
104 |
105 | #### `runtime.add( String name, Object shader )`
106 |
107 | If your shader data is already loaded in JSON form by some other means, you can add it to the runtime's repository of known shaders with this method.
108 |
109 | #### `runtime.get( String name )`
110 |
111 | The ShaderFrog runtime stores materials by name. This function returns a **new instance** of the material you have loaded. You can assign this new material to your object, update uniforms on it, etc.
112 |
113 | ## Proposed Shader Format
114 |
115 | [ShaderFrog](http://shaderfrog.com) requires a shader file format to transfer all neccessary shader data from the editor to the end user. A proposed JSON format is discussed in [THREE_SHADER_FORMAT.md](https://github.com/AndrewRayCode/ShaderFrog-Runtime/blob/master/THREE_SHADER_FORMAT.md).
116 |
117 | ## Development
118 |
119 | To install the dependencies:
120 |
121 | git clone https://github.com/AndrewRayCode/ShaderFrog-Runtime
122 | npm install
123 |
124 | To build the distributable Javascript file:
125 |
126 | npm run build
127 |
--------------------------------------------------------------------------------
/src/ShaderRuntime.js:
--------------------------------------------------------------------------------
1 | import * as THREE from 'three';
2 |
3 | let defaultThreeUniforms = [
4 | 'normalMatrix', 'viewMatrix', 'projectionMatrix', 'position', 'normal',
5 | 'modelViewMatrix', 'uv', 'uv2', 'modelMatrix'
6 | ];
7 |
8 | function ShaderRuntime() {}
9 |
10 | ShaderRuntime.prototype = {
11 |
12 | mainCamera: null,
13 | cubeCameras: {},
14 |
15 | reserved: { time: null, cameraPosition: null },
16 |
17 | umap: {
18 | float: { type: 'f', value: 0 },
19 | int: { type: 'i', value: 0 },
20 | vec2: { type: 'v2', value() { return new THREE.Vector2(); } },
21 | vec3: { type: 'v3', value() { return new THREE.Vector3(); } },
22 | vec4: { type: 'v4', value() { return new THREE.Vector4(); } },
23 | samplerCube: { type: 't' },
24 | sampler2D: { type: 't' }
25 | },
26 |
27 | getUmap( type ) {
28 | let value = this.umap[ type ].value;
29 | return typeof value === 'function' ? value() : value;
30 | },
31 |
32 | load( sourceOrSources, callback ) {
33 |
34 | let sources = sourceOrSources,
35 | onlyOneSource = typeof sourceOrSources === 'string';
36 |
37 | if( onlyOneSource ) {
38 | sources = [ sourceOrSources ];
39 | }
40 |
41 | let loadedShaders = new Array( sources.length ),
42 | itemsLoaded = 0;
43 |
44 | let loadSource = ( index, source ) => {
45 |
46 | let loader = new THREE.XHRLoader();
47 | loader.load( source, ( json ) => {
48 |
49 | let parsed;
50 | try {
51 | parsed = JSON.parse( json );
52 | delete parsed.id; // Errors if passed to rawshadermaterial :(
53 | } catch( e ) {
54 | throw new Error( 'Could not parse shader' + source + '! Please verify the URL is correct.' );
55 | }
56 | this.add( parsed.name, parsed );
57 | loadedShaders[ index ] = parsed;
58 |
59 | if( ++itemsLoaded === sources.length ) {
60 | callback( onlyOneSource ? loadedShaders[ 0 ] : loadedShaders );
61 | }
62 |
63 | });
64 | };
65 |
66 | for( let x = 0; x < sources.length; x++ ) {
67 | loadSource( x, sources[ x ] );
68 | }
69 |
70 | },
71 |
72 | registerCamera( camera ) {
73 |
74 | if( !( camera instanceof THREE.Camera ) ) {
75 | throw new Error( 'Cannot register a non-camera as a camera!' );
76 | }
77 |
78 | this.mainCamera = camera;
79 |
80 | },
81 |
82 | registerCubeCamera( name, camera ) {
83 |
84 | if( !camera.renderTarget ) {
85 | throw new Error( 'Cannot register a non-camera as a camera!' );
86 | }
87 |
88 | this.cubeCameras[ name ] = camera;
89 |
90 | },
91 |
92 | unregisterCamera( name ) {
93 |
94 | if( name in this.cubeCameras ) {
95 |
96 | delete this.cubeCameras[ name ];
97 |
98 | } else if( name === this.mainCamera ) {
99 |
100 | delete this.mainCamera;
101 |
102 | } else {
103 |
104 | throw new Error( 'You never registered camera ' + name );
105 |
106 | }
107 |
108 | },
109 |
110 | updateSource( identifier, config, findBy ) {
111 |
112 | findBy = findBy || 'name';
113 |
114 | if( !this.shaderTypes[ identifier ] ) {
115 | throw new Error( 'Runtime Error: Cannot update shader ' + identifier + ' because it has not been added.' );
116 | }
117 |
118 | let newShaderData = this.add( identifier, config ),
119 | shader, x;
120 |
121 | for( x = 0; shader = this.runningShaders[ x++ ]; ) {
122 | if( shader[ findBy ] === identifier ) {
123 | extend( shader.material, omit( newShaderData, 'id' ) );
124 | shader.material.needsUpdate = true;
125 | }
126 | }
127 |
128 | },
129 |
130 | renameShader( oldName, newName ) {
131 |
132 | let x, shader;
133 |
134 | if( !( oldName in this.shaderTypes ) ) {
135 | throw new Error('Could not rename shader ' + oldName + ' to ' + newName + '. It does not exist.');
136 | }
137 |
138 | this.shaderTypes[ newName ] = this.shaderTypes[ oldName ];
139 | delete this.shaderTypes[ oldName ];
140 |
141 | for( x = 0; shader = this.runningShaders[ x++ ]; ) {
142 | if( shader.name === oldName ) {
143 | shader.name = newName;
144 | }
145 | }
146 |
147 | },
148 |
149 | get( identifier ) {
150 |
151 | let shaderType = this.shaderTypes[ identifier ];
152 |
153 | if( !shaderType.initted ) {
154 |
155 | this.create( identifier );
156 | }
157 |
158 | return shaderType.material;
159 |
160 | },
161 |
162 | add( shaderName, config ) {
163 |
164 | let newData = clone( config ),
165 | uniform;
166 | newData.fragmentShader = config.fragment;
167 | newData.vertexShader = config.vertex;
168 | delete newData.fragment;
169 | delete newData.vertex;
170 |
171 | for( var uniformName in newData.uniforms ) {
172 | uniform = newData.uniforms[ uniformName ];
173 | if( uniform.value === null ) {
174 | newData.uniforms[ uniformName ].value = this.getUmap( uniform.glslType );
175 | }
176 | }
177 |
178 | if( shaderName in this.shaderTypes ) {
179 | // maybe not needed? too sleepy, need document
180 | extend( this.shaderTypes[ shaderName ], newData );
181 | } else {
182 | this.shaderTypes[ shaderName ] = newData;
183 | }
184 |
185 | return newData;
186 |
187 | },
188 |
189 | create( identifier ) {
190 |
191 | let shaderType = this.shaderTypes[ identifier ];
192 | let keys = Object.keys( shaderType );
193 |
194 | // Three's shadermaterial id is not assignable, so filter it out
195 | let withoutId = {};
196 | for( let i = 0; i < keys.length; i++ ) {
197 | if( keys[ i ] !== 'id' ) {
198 | withoutId[ keys[ i ] ] = shaderType[ keys[ i ] ];
199 | }
200 | }
201 |
202 | shaderType.material = new THREE.RawShaderMaterial( withoutId );
203 |
204 | this.runningShaders.push( shaderType );
205 |
206 | shaderType.init && shaderType.init( shaderType.material );
207 | shaderType.material.needsUpdate = true;
208 |
209 | shaderType.initted = true;
210 |
211 | return shaderType.material;
212 |
213 | },
214 |
215 | updateRuntime( identifier, data, findBy ) {
216 |
217 | findBy = findBy || 'name';
218 |
219 | let shader, x, uniformName, uniform;
220 |
221 | // This loop does not appear to be a slowdown culprit
222 | for( x = 0; shader = this.runningShaders[ x++ ]; ) {
223 | if( shader[ findBy ] === identifier ) {
224 | for( uniformName in data.uniforms ) {
225 |
226 | if( uniformName in this.reserved ) {
227 | continue;
228 | }
229 |
230 | if( uniformName in shader.material.uniforms ) {
231 |
232 | uniform = data.uniforms[ uniformName ];
233 |
234 | // this is nasty, since the shader serializes
235 | // CubeCamera model to string. Maybe not update it at
236 | // all?
237 | if( uniform.type === 't' && typeof uniform.value === 'string' ) {
238 | uniform.value = this.cubeCameras[ uniform.value ].renderTarget;
239 | }
240 |
241 | shader.material.uniforms[ uniformName ].value = data.uniforms[ uniformName ].value;
242 | }
243 | }
244 | }
245 | }
246 |
247 | },
248 |
249 | // Update global shader uniform values
250 | updateShaders( time, obj ) {
251 |
252 | let shader, x;
253 |
254 | obj = obj || {};
255 |
256 | for( x = 0; shader = this.runningShaders[ x++ ]; ) {
257 |
258 | for( let uniform in obj.uniforms ) {
259 | if( uniform in shader.material.uniforms ) {
260 | shader.material.uniforms[ uniform ].value = obj.uniforms[ uniform ];
261 | }
262 | }
263 |
264 | if( 'cameraPosition' in shader.material.uniforms && this.mainCamera ) {
265 |
266 | shader.material.uniforms.cameraPosition.value = this.mainCamera.position.clone();
267 |
268 | }
269 |
270 | if( 'viewMatrix' in shader.material.uniforms && this.mainCamera ) {
271 |
272 | shader.material.uniforms.viewMatrix.value = this.mainCamera.matrixWorldInverse;
273 |
274 | }
275 |
276 | if( 'time' in shader.material.uniforms ) {
277 |
278 | shader.material.uniforms.time.value = time;
279 |
280 | }
281 |
282 | }
283 |
284 | },
285 |
286 | shaderTypes: {},
287 |
288 | runningShaders: []
289 |
290 | };
291 |
292 | // Convenience methods so we don't have to include underscore
293 | function extend() {
294 | let length = arguments.length,
295 | obj = arguments[ 0 ];
296 |
297 | if( length < 2 ) {
298 | return obj;
299 | }
300 |
301 | for( let index = 1; index < length; index++ ) {
302 | let source = arguments[ index ],
303 | keys = Object.keys( source || {} ),
304 | l = keys.length;
305 | for( let i = 0; i < l; i++ ) {
306 | let key = keys[i];
307 | obj[ key ] = source[ key ];
308 | }
309 | }
310 |
311 | return obj;
312 | }
313 |
314 | function clone( obj ) {
315 | return extend( {}, obj );
316 | }
317 |
318 | function omit( obj, ...keys ) {
319 | let cloned = clone( obj ), x, key;
320 | for( x = 0; key = keys[ x++ ]; ) {
321 | delete cloned[ key ];
322 | }
323 | return cloned;
324 | }
325 |
326 | export default ShaderRuntime;
327 |
--------------------------------------------------------------------------------