Learning 3D Graphics With Three.js | Advanced Materials and Custom Shaders by clayjohn

View this thread on steempeak.com
· @clayjohn · (edited)
$53.58
Learning 3D Graphics With Three.js | Advanced Materials and Custom Shaders
#### What Will I Learn?

- You will learn what a ```Material``` is in three.js
- What they are used for
- The various types and when you might want to use each
- How to put together a custom shader using bits and pieces from threejs's ```ShaderChunk``` library

#### Requirements

- Basic familiarity with three.js
- Basic programming knowledge
- Any machine with a webgl compatible web browser
- Knowledge on how to run javascript code (either locally or using something like a [jsfiddle](https://jsfiddle.net))

#### Difficulty

- Basic

#### Tutorial Contents
When I first began using three.js I didn't understand the differences between the materials or why they were significant. I especially didn't understand the purpose behind the ```ShaderMaterial``` let alone how to use it. I hope to shed some light on these topics and teach you how to go from very little knowledge about materials to writing your own custom ```ShaderMaterial``` in three.js.

Materials are a very important part of any 3D scene. They define how to draw the objects that you submit to the renderer to draw. They take information such as color and reflectivity of a surface and define how it should look in a scene given other properties such as lighting or fog.

Materials are an extension of vertex and fragment shaders. If you don't know what those are don't worry, they are something that you use in lower level frameworks to tell the computer how to draw objects. A Material encapsulates information about what to do with a) geometry data (how it is to be placed in the final screen) and b) how the surface interacts with lights and other objects in the scene. In three.js this information is represented by things like color, reflectivity, roughness, transparency, etc. depending on the specific ```Material``` used.

Materials are made up of two main components; the vertex shader and the fragment shader. In three.js we use Materials as a way of abstracting away from these low level concepts. Shaders are essentially miniature programs which are meant to be executed on the GPU. Vertex shaders take per-vertex information and return where on the screen a given vertex should be placed given model and camera information. A fragment shader determines what color each final pixel of an image should be. It uses information passed in by the vertex shader and information passed in uniformly to both shaders. Since we are using three.js you do not need to worry about either of these concepts, three.js hides them nicely for you so you can focus on what you want your objects to look like, not on learning a whole new language.  

For this tutorial we will be focussing on comparing the various types of Materials that three.js has to offer. To begin we will set up the basic structure of our program. If this looks unfamiliar to you or you don't understand where this is supposed to go I recommend you familiarize yourself with the basic structure of three.js. You can see an example of how a scene works [here](https://threejs.org/docs/index.html#manual/introduction/Creating-a-scene).

```javascript
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, 1, 1, 4 );
scene.background = new THREE.Color(0x77aadd);

var renderer = new THREE.WebGLRenderer({antialias: true, preserveDrawingBuffer: true});
renderer.setSize( 512, 512 );
document.body.appendChild( renderer.domElement );
			
var light = new THREE.PointLight( );
light.position.set( 5, 5, 5 );
scene.add( light );

camera.position.z = 2;
renderer.render(scene, camera);
```

Starting from this as a base we will be adding a mesh to the scene like so:
```javascript
var geometry = new THREE.TorusKnotGeometry(0.5, 0.2, 128, 32);
//add a material here
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
```
For each material simply replace the middle line with the material definition to see what it will look like.

##### Abstract Material
The abstract ```Material``` class is the parent to the other material classes in three.js. It contains properties and methods that are accessible by all other material classes. The basic form of instantiating a ```Material``` derived class is
```javascript
var material = new THREE.MeshTypeMaterial({/*property: value*/});
```
As you can see it is very simple, it gets complicated once you start passing in many different properties as you will often do for some of the other types of materials.

##### Common Materials
###### MeshBasicMaterial
The [```MeshBasicMaterial```](https://threejs.org/docs/index.html#api/materials/MeshBasicMaterial) essentially assigns the object a single color and ignores all other aspects of coloring and shading. Although it still inherits all the properties from ```Material``` including rendering in wireframe etc. The ```MeshBasicMaterial``` true to its name is the most basic of the materials in three.js. It is best for when you want a lot of speed and you are okay with not having complex shading or other effects. An example instantiation would look like:
```javascript
var basic_material = new THREE.MeshBasicMaterial({color: 0xee8866});
```
![][Mesh Basic Material]

###### MeshDepthMaterial
The [```MeshDepthMaterial```](https://threejs.org/docs/index.html#api/materials/MeshDepthMaterial) is used to display the distance between the camera and the point of the object that is being shaded. ```MeshDepthMaterial``` typically uses no parameters to instantiate so it looks like this:
```javascript
var depth_material = new THREE.MeshDepthMaterial(); 
```
![][Mesh Depth Material]

###### MeshNormalMaterial
The [```MeshNormalMaterial```](https://threejs.org/docs/index.html#api/materials/MeshNormalMaterial) is used to display the normals of the object you are rendering. It is very useful for debugging an object's normals directly. As with ```MeshDepthMaterial```, ```MeshNormalMaterial``` typically does not take arguments unless you want to use one of the standard ones built into ```Material``` such as ```wiredframe```. Let's look at how that would work.

First a regular ```Mesh``` with standard parameters:
```javascript
var normal_material = new THREE.MeshNormalMaterial();
```
![][Mesh Normal Material]

Now with the ```wireframe``` property set to true:
```javascript
var normal_material = new THREE.MeshNormalMaterial({wireframe: true});
```
![][Mesh Normal Wireframe Material]

###### MeshLambertMaterial
The [```MeshLambertMaterial```](https://threejs.org/docs/index.html#api/materials/MeshLambertMaterial) is the most basic of the materials that take into account lighting. The ```MeshLambertMaterial``` uses the lambertian shading model to determine how to shade the object. Which means you will get ambient and diffuse shading but no specular highlights. Additionally it uses Gouraud shading which means that the lighting calculation is computed for each vertex and then interpolated across the triangle. It is fairly similar to ```MeshPhongMaterial``` but since the calculation is performed once per vertex instead of once per pixel and it doesn't compute a specular highlight it is significantly faster at a reduced visual quality.

```javascript
var lambert_material = new THREE.MeshLambertMaterial({color: 0xee8866});
```

![][Mesh Lambert Material]

```MeshLambertMaterial``` doesn't have very many parameters either. It is a fairly basic material. Try turning off the property ```depthTest``` by setting it to ```false```. This is something that can be done with any ```Material``` derived materials in threejs.
```javascript
var lambert_material = new THREE.MeshLambertMaterial({color: 0xee8866, depthTest: false});
```

###### MeshPhongMaterial
The [```MeshPhongMaterial```](https://threejs.org/docs/index.html#api/materials/MeshPhongMaterial) using the Phong shading model and is calculated per-pixel. It used to be the standard formula for shading algorithms until Physically Based Materials took over. It is significantly cheaper than the ```MeshStandardMaterial``` but uses a lot of approximations as a result. That being said it is very powerful especially when attention is paid to its various parameters and/or when combined with textures.

```javascript
var phong_material = new THREE.MeshPhongMaterial({color: 0xee8866});
```

![][Mesh Phong Material]

Here is the same object with the ```flatShading``` parameter set to ```true```

```javascript
var phong_material = new THREE.MeshPhongMaterial({color: 0xee8866, flatShading: true});
```

![][Mesh Phong Flat Material]

Try playing with the ```shininess``` parameter to see how it affects the material. Notice how at 0 it looks like the ```MeshLambertionMaterial``` and at 100 it looks like shiny plastic.

###### MeshToonMaterial
The [```MeshToonMaterial```](https://threejs.org/docs/index.html#api/materials/MeshToonMaterial) is built on a very similar model to the ```MeshPhongMaterial``` except it uses a more restricted color palette. Therefore you get bands of solid color rather than the continuous shading you see in the ```MeshPhongMaterial```. It is used for more stylized graphics.

```javascript
var toon_material = new THREE.MeshToonMaterial({color: 0xee8866});
```

![][Mesh Toon Material]

###### MeshStandardMaterial
The [```MeshStandardMaterial```](https://threejs.org/docs/index.html#api/materials/MeshStandardMaterial) implements Physically Based Rendering (PBR) techniques to shade an object in a more physically correct way. If you are looking to create realistic graphics this is the material for you. You have fine tuned control over many properties that will allow you to closely match real materials. The two most prominent parameters are ```roughness``` and ```metalness``` they each vary from 0-1 and affect the look of the object greatly. 

```javascript
var standard_material = new THREE.MeshStandardMaterial({color:0xee8866})
```

Object rendered with standard parameters ```roughness = 0.5``` and ```metalness = 0.5```

![][Mesh Standard Material]

```metalness``` increases from 0-1 from left to right and ```roughness``` increases from 0-1 from top to bottom

![][PBR Comparison]

Notice that with high roughness and low metalness you are back to the basic Phong/Lambertion style shading.

To get the most out of the ```MeshStandardMaterial``` you will want to set an environment map. You do so by setting the ```envMap``` property to a ```CubeTexture```.

Note: The [```MeshPhysicalMaterial```](https://threejs.org/docs/index.html#api/materials/MeshPhysicalMaterial) is an extension of the ```MeshStandardMaterial``` that has more fine tuned reflectivity properties.

##### Advanced Materials
###### ShaderMaterial
The [```ShaderMaterial```](https://threejs.org/docs/index.html#api/materials/ShaderMaterial) allows you to write your own shaders

ShaderMaterials have a bit more complicated usage than the other materials

```javascript
var material = new THREE.ShaderMaterial({
	uniforms: {
  	time: {value: 0},
		color: { value: new THREE.Color( 0xffffff) }
	},
	vertexShader: vertexShaderSource, //string containing vertex shader code
	fragmentShader: fragmentShaderSource //string containing fragment shader code
});
```

Using the ```ShaderMaterial``` you can come up with all kinds of custom effects that are not possible with standard materials. For example below is a picture of a little white planet with a blue atmosphere. This picture was drawn using a single sphere. The picture below it is using the same geometry but has the ```MeshPhongMaterial``` applied.

![][Shader Material]

![][Phong Sphere]

As you can see the ability to write your own shaders gives you a lot of flexibility to do special effects that would otherwise be unavailable to you. You can also use them to make cheap animations. The following gif uses the same material above, but is drawn in a scene with no lights. Everything is faked within the shader.

![][Atmosphere Gif]

###### Making Your Own ShaderMaterial
The easiest way to make your own ```ShaderMaterial``` is by using three.js's built in [```ShaderChunk```](https://threejs.org/docs/index.html#api/renderers/shaders/ShaderChunk). The ```ShaderChunk``` class is essentially a library of common shader code that can be mixed and matched to create your own shaders, or that can be added to your shader to avoid writing common shader stuff such as lighting calculations. To access it you just use: 

```javascript
THREE.ShaderChunk["name_of_ShaderChunk"]
``` 
or you can use dot notation 
```javascript
THREE.ShaderChunk.name_of_ShaderChunk
``` 

Let's do an example, suppose you wanted to add fog to a custom shader you might instantiate your material like so:
```javascript
var material = new THREE.ShaderMaterial({
	uniforms: {
  	time: {value: 0},
		color: { value: new THREE.Color( 0xffffff) }
	},
	vertexShader: THREE.ShaderChunk.common + THREE.ShaderChunk.fog_pars_vertex + vertexShaderSource, 
	fragmentShader: THREE.ShaderChunk.common + THREE.ShaderChunk.fog_pars_vertex + fragmentShaderSource 
});
```

This will allow you to access any of the fog parameters and functions within your own shader. Unfortunately, this is not everything you need to do. In order to render with Fog we need to access certain uniform variables and we need to calculate the fog within the shader. The first is much easier to do, let's look at how to do that. 

In order to access the fog uniform variables we just have to combine them with our own custom variables, we do this with the ```THREE.UniformsUtils``` function ```merge``` and the ```UniformsLib``` which functions very similarly to ShaderChunks. With this added bit our example now looks like:
 ```javascript
var material = new THREE.ShaderMaterial({
	uniforms: THREE.UniformsUtils.merge( [
    THREE.UniformsLib[ "fog" ],
		{
  		time: {value: 0},
			color: { value: new THREE.Color( 0xffffff) }
		}
	]),
	vertexShader: THREE.ShaderChunk.common + THREE.ShaderChunk.fog_pars_vertex + vertexShaderSource, 
	fragmentShader: THREE.ShaderChunk.common + THREE.ShaderChunk.fog_pars_vertex + fragmentShaderSource 
});
```
This will add the fog uniforms to our own so that we can access them in our shaders. All that remains to be done now is to actually utilize the fog parameters and uniforms in our shaders. They will be just as accessible as variables and functions you define yourself. There is a ```ShaderChunk``` that will perform the calculations for you as well. But it must be embedded when you create the shader. Let's look at a minimal example of how that would look:

```javascript
var fragmentShader = [
  "uniform vec3 color;",

  THREE.ShaderChunk[ "common" ],
  THREE.ShaderChunk[ "fog_pars_fragment" ],
  
  "void main() {",
    "gl_FragColor = vec4(color, 1.0);",
    THREE.ShaderChunk[ "fog_fragment" ],
  "}"

].join("\n"),

var vertexShader = [
	THREE.ShaderChunk[ "fog_pars_vertex" ],
  THREE.ShaderChunk[ "common" ],

  "void main() {",
    "vec4 mvPosition = modelViewMatrix * vec4( position.xyz, 1.0 );",
    "gl_Position = projectionMatrix * mvPosition;",
    THREE.ShaderChunk[ "fog_vertex" ],
  "}"

].join("\n")
```

Don't worry if you don't understand everything that is going on here. The important things to note are how the shader code is written line by line as individual comma-separated strings, and how the ShaderChunks are embedded directly into shader code. 

Putting it all together we end up with a ```ShaderMaterial``` definition exactly like the first one. You can see that the calls to ```THREE.ShaderChunk``` are hidden away.

And with that, you should have everything you need to start writing your own custom shaders for three.js.

###### RawShaderMaterial
The [```RawShaderMaterial```](https://threejs.org/docs/index.html#api/materials/RawShaderMaterial) is really where the rubber meets the road. With a ```ShaderMaterial``` you can still access all the default information that three.js makes available. With the ```RawShaderMaterial``` you have to do everything yourself. This makes it significantly more lightweight but also requires that you do a lot more work yourself.

##### Summary
That's it! There are a few other types of materials that are available in three.js but these are the common ones you will likely want to use. 

Hopefully you have learned:

- The basic material types in three.js and how they are used
- how to set up your own custom material using ```ShaderMaterial``` and ```ShaderChunk```

##### Further Reading
If you are interested more in learning about shaders I suggest you work your way through [The Book of Shaders](https://thebookofshaders.com/) and check out [Shadertoy](shadertoy.com).   


[Mesh Basic Material]: https://i.imgur.com/f5lIxQr.png
[Mesh Depth Material]: https://i.imgur.com/fLkZ2NP.png
[Mesh Normal Material]: https://i.imgur.com/9AmtEGu.png
[Mesh Normal Wireframe Material]: https://i.imgur.com/XiQNF0B.png
[Mesh Lambert Material]: https://i.imgur.com/OTmiF8q.png
[Mesh Phong Material]: https://i.imgur.com/mtDwd40.png
[Mesh Phong Flat Material]: https://i.imgur.com/o1sdStU.png
[Mesh Toon Material]: https://i.imgur.com/IC8B6nh.png
[Mesh Standard Material]: https://i.imgur.com/fd1rk9m.png
[PBR Comparison]: https://i.imgur.com/pkjXzF3.png
[Shader Material]: https://i.imgur.com/wI0gqD4.png
[Phong Sphere]: https://i.imgur.com/dJA3Qk1.png
[Atmosphere Gif]: https://i.imgur.com/y72GfXK.gif

<br /><hr/><em>Posted on <a href="https://utopian.io/utopian-io/@clayjohn/learning-3d-graphics-with-three-js-or-advanced-materials-and-custom-shaders">Utopian.io -  Rewarding Open Source Contributors</a></em><hr/>
👍  , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,
properties (23)
post_id39,021,395
authorclayjohn
permlinklearning-3d-graphics-with-three-js-or-advanced-materials-and-custom-shaders
categoryutopian-io
json_metadata"{"repository": {"owner": {"login": "mrdoob"}, "id": 576201, "full_name": "mrdoob/three.js", "fork": false, "name": "three.js", "html_url": "https://github.com/mrdoob/three.js"}, "moderator": {"pending": false, "account": "scipio", "reviewed": true, "flagged": false, "time": "2018-03-17T13:42:56.495Z"}, "format": "markdown", "platform": "github", "tags": ["utopian-io", "programming", "gamedev", "steemstem", "steemdev"], "questions": [{"selected": 0, "question": "Is the project description formal?", "answers": [{"value": "Yes it\u2019s straight to the point", "score": 10, "selected": true}, {"value": "Need more description ", "score": 5, "selected": false}, {"value": "Not too descriptive", "score": 0, "selected": false}]}, {"selected": 0, "question": "Is the language / grammar correct?", "answers": [{"value": "Yes", "score": 20, "selected": true}, {"value": "A few mistakes", "score": 10, "selected": false}, {"value": "It's pretty bad", "score": 0, "selected": false}]}, {"selected": 0, "question": "Was the template followed?", "answers": [{"value": "Yes", "score": 10, "selected": true}, {"value": "Partially", "score": 5, "selected": false}, {"value": "No", "score": 0, "selected": false}]}, {"selected": 0, "question": "Is there information about the additional frameworks?", "answers": [{"value": "Yes, everything is explained", "score": 5, "selected": true}, {"value": "Yes, but not enough", "score": 3, "selected": false}, {"value": "No details at all", "score": 0, "selected": false}]}, {"selected": 0, "question": "Is there code in the tutorial?", "answers": [{"value": "Yes, and it\u2019s well explained", "score": 5, "selected": true}, {"value": "Yes, but no explanation", "score": 3, "selected": false}, {"value": "No", "score": 0, "selected": false}]}, {"selected": 0, "question": "Is the tutorial explains technical aspects well enough?", "answers": [{"value": "Yes, it teaches how and why about technical aspects", "score": 5, "selected": true}, {"value": "Yes, but it\u2019s not good/enough", "score": 3, "selected": false}, {"value": "No, it explains poorly", "score": 0, "selected": false}]}, {"selected": 0, "question": "Is the tutorial general and dense enough?", "answers": [{"value": "Yes, it\u2019s general and dense", "score": 5, "selected": true}, {"value": "Kinda, it might be more generalized", "score": 3, "selected": false}, {"value": "No, it\u2019s sliced unnecessarily to keep part number high", "score": 0, "selected": false}]}, {"selected": 0, "question": "Is there an outline for the tutorial content at the beginning of the post", "answers": [{"value": "Yes, there is a well prepared outline in \u201cWhat will I learn?\u201d or another outline section", "score": 5, "selected": true}, {"value": "Yes, but there is no proper listing for every step of the tutorial or it\u2019s not detailed enough", "score": 3, "selected": false}, {"value": "No, there is no outline for the steps.", "score": 0, "selected": false}]}, {"selected": 0, "question": "Is the visual content of good quality?", "answers": [{"value": "Yes", "score": 5, "selected": true}, {"value": "Yes, but bad quality", "score": 3, "selected": false}, {"value": "No", "score": 0, "selected": false}]}, {"selected": 2, "question": "Is this a tutorial series?", "answers": [{"value": "Yes", "score": 5, "selected": false}, {"value": "Yes, but first part", "score": 3, "selected": false}, {"value": "No", "score": 0, "selected": true}]}, {"selected": 0, "question": "Is the tutorial post structured?", "answers": [{"value": "Yes", "score": 5, "selected": true}, {"value": "Not so good", "score": 3, "selected": false}, {"value": "No", "score": 0, "selected": false}]}], "community": "utopian", "type": "tutorials", "pullRequests": [], "links": ["https://jsfiddle.net", "https://threejs.org/docs/index.html#manual/introduction/Creating-a-scene", "https://threejs.org/docs/index.html#api/materials/MeshBasicMaterial", "https://threejs.org/docs/index.html#api/materials/MeshDepthMaterial", "https://threejs.org/docs/index.html#api/materials/MeshNormalMaterial", "https://threejs.org/docs/index.html#api/materials/MeshLambertMaterial", "https://threejs.org/docs/index.html#api/materials/MeshPhongMaterial", "https://threejs.org/docs/index.html#api/materials/MeshToonMaterial", "https://threejs.org/docs/index.html#api/materials/MeshStandardMaterial", "https://threejs.org/docs/index.html#api/materials/MeshPhysicalMaterial", "https://threejs.org/docs/index.html#api/materials/ShaderMaterial", "https://threejs.org/docs/index.html#api/renderers/shaders/ShaderChunk", "https://threejs.org/docs/index.html#api/materials/RawShaderMaterial", "https://thebookofshaders.com/"], "app": "utopian/1.0.0", "score": 98}"
created2018-03-17 05:53:51
last_update2018-03-17 13:42:57
depth0
children7
net_rshares18,506,825,091,143
last_payout2018-03-24 05:53:51
cashout_time1969-12-31 23:59:59
total_payout_value37.122 SBD
curator_payout_value16.456 SBD
pending_payout_value0.000 SBD
promoted0.000 SBD
body_length17,467
author_reputation12,492,997,891,187
root_title"Learning 3D Graphics With Three.js | Advanced Materials and Custom Shaders"
beneficiaries
0.
accountutopian.pay
weight2,500
max_accepted_payout1,000,000.000 SBD
percent_steem_dollars10,000
author_curate_reward""
vote details (35)
@scipio ·
$0.37
Thank you for the contribution. It has been approved.

**PS:**
I really like your sentence _`I hope to shed some light on these topics`_ , considering it's all about shading! ;-)

You can contact us on [Discord](https://discord.gg/uTyJkNm).
**[[utopian-moderator]](https://utopian.io/moderators)**
👍  , ,
properties (23)
post_id39,077,402
authorscipio
permlinkre-clayjohn-learning-3d-graphics-with-three-js-or-advanced-materials-and-custom-shaders-20180317t134333907z
categoryutopian-io
json_metadata"{"app": "utopian/1.0.0", "community": "utopian", "tags": ["utopian-io"]}"
created2018-03-17 13:43:33
last_update2018-03-17 13:43:33
depth1
children1
net_rshares105,576,264,321
last_payout2018-03-24 13:43:33
cashout_time1969-12-31 23:59:59
total_payout_value0.280 SBD
curator_payout_value0.088 SBD
pending_payout_value0.000 SBD
promoted0.000 SBD
body_length297
author_reputation32,029,897,993,437
root_title"Learning 3D Graphics With Three.js | Advanced Materials and Custom Shaders"
beneficiaries[]
max_accepted_payout1,000,000.000 SBD
percent_steem_dollars10,000
author_curate_reward""
vote details (3)
@clayjohn ·
Thank you @scipio! I'm glad you caught that.
properties (22)
post_id39,177,524
authorclayjohn
permlinkre-scipio-re-clayjohn-learning-3d-graphics-with-three-js-or-advanced-materials-and-custom-shaders-20180318t035147552z
categoryutopian-io
json_metadata"{"app": "steemit/0.1", "users": ["scipio"], "tags": ["utopian-io"]}"
created2018-03-18 03:51:48
last_update2018-03-18 03:51:48
depth2
children0
net_rshares0
last_payout2018-03-25 03:51:48
cashout_time1969-12-31 23:59:59
total_payout_value0.000 SBD
curator_payout_value0.000 SBD
pending_payout_value0.000 SBD
promoted0.000 SBD
body_length44
author_reputation12,492,997,891,187
root_title"Learning 3D Graphics With Three.js | Advanced Materials and Custom Shaders"
beneficiaries[]
max_accepted_payout1,000,000.000 SBD
percent_steem_dollars10,000
@utopian-io ·
### Hey @clayjohn I am @utopian-io. I have just upvoted you!
#### Achievements
- You have less than 500 followers. Just gave you a gift to help you succeed!
- This is your first accepted contribution here in Utopian. Welcome!
#### Community-Driven Witness!
I am the first and only Steem Community-Driven Witness. <a href="https://discord.gg/zTrEMqB">Participate on Discord</a>. Lets GROW TOGETHER!
- <a href="https://v2.steemconnect.com/sign/account-witness-vote?witness=utopian-io&approve=1">Vote for my Witness With SteemConnect</a>
- <a href="https://v2.steemconnect.com/sign/account-witness-proxy?proxy=utopian-io&approve=1">Proxy vote to Utopian Witness with SteemConnect</a>
- Or vote/proxy on <a href="https://steemit.com/~witnesses">Steemit Witnesses</a>

[![mooncryption-utopian-witness-gif](https://steemitimages.com/DQmYPUuQRptAqNBCQRwQjKWAqWU3zJkL3RXVUtEKVury8up/mooncryption-s-utopian-io-witness-gif.gif)](https://steemit.com/~witnesses)

**Up-vote this comment to grow my power and help Open Source contributions like this one. Want to chat? Join me on Discord https://discord.gg/Pc8HG9x**
👍  
properties (23)
post_id39,176,992
authorutopian-io
permlinkre-clayjohn-learning-3d-graphics-with-three-js-or-advanced-materials-and-custom-shaders-20180318t034604827z
categoryutopian-io
json_metadata"{"app": "utopian/1.0.0", "community": "utopian", "tags": ["utopian-io"]}"
created2018-03-18 03:46:03
last_update2018-03-18 03:46:03
depth1
children0
net_rshares542,089,725
last_payout2018-03-25 03:46:03
cashout_time1969-12-31 23:59:59
total_payout_value0.000 SBD
curator_payout_value0.000 SBD
pending_payout_value0.000 SBD
promoted0.000 SBD
body_length1,103
author_reputation152,913,012,544,965
root_title"Learning 3D Graphics With Three.js | Advanced Materials and Custom Shaders"
beneficiaries[]
max_accepted_payout1,000,000.000 SBD
percent_steem_dollars10,000
author_curate_reward""
vote details (1)
@arcange ·
Congratulations @clayjohn!
Your post was mentioned in the [Steemit Hit Parade for newcomers](https://steemit.com/hit-parade/@arcange/daily-hit-parade-for-newcomers-20180317) in the following category:

* Pending payout - Ranked 3 with $ 60,35

I also upvoted your post to increase its reward
If you like my work to promote newcomers and give them more visibility on Steemit, feel free to vote for my witness! You can do it [here](https://steemit.com/~witnesses) or use [SteemConnect](https://v2.steemconnect.com/sign/account-witness-vote?witness=arcange&approve=1)
👍  
properties (23)
post_id39,266,500
authorarcange
permlinkre-learning-3d-graphics-with-three-js-or-advanced-materials-and-custom-shaders-20180317t172227000z
categoryutopian-io
json_metadata{}
created2018-03-18 16:22:30
last_update2018-03-18 16:22:30
depth1
children0
net_rshares597,217,494
last_payout2018-03-25 16:22:30
cashout_time1969-12-31 23:59:59
total_payout_value0.000 SBD
curator_payout_value0.000 SBD
pending_payout_value0.000 SBD
promoted0.000 SBD
body_length564
author_reputation231,443,210,169,699
root_title"Learning 3D Graphics With Three.js | Advanced Materials and Custom Shaders"
beneficiaries[]
max_accepted_payout1,000,000.000 SBD
percent_steem_dollars10,000
author_curate_reward""
vote details (1)
@steemitboard ·
Congratulations @clayjohn! You have completed some achievement on Steemit and have been rewarded with new badge(s) :

[![](https://steemitimages.com/70x80/http://steemitboard.com/notifications/votes.png)](http://steemitboard.com/@clayjohn) Award for the number of upvotes

Click on any badge to view your own Board of Honor on SteemitBoard.
For more information about SteemitBoard, click [here](https://steemit.com/@steemitboard)

If you no longer want to receive notifications, reply to this comment with the word `STOP`

> Upvote this notification to help all Steemit users. Learn why [here](https://steemit.com/steemitboard/@steemitboard/http-i-cubeupload-com-7ciqeo-png)!
properties (22)
post_id39,497,945
authorsteemitboard
permlinksteemitboard-notify-clayjohn-20180319t225659000z
categoryutopian-io
json_metadata"{"image": ["https://steemitboard.com/img/notifications.png"]}"
created2018-03-19 22:57:00
last_update2018-03-19 22:57:00
depth1
children0
net_rshares0
last_payout2018-03-26 22:57:00
cashout_time1969-12-31 23:59:59
total_payout_value0.000 SBD
curator_payout_value0.000 SBD
pending_payout_value0.000 SBD
promoted0.000 SBD
body_length675
author_reputation38,705,954,145,809
root_title"Learning 3D Graphics With Three.js | Advanced Materials and Custom Shaders"
beneficiaries[]
max_accepted_payout1,000,000.000 SBD
percent_steem_dollars10,000
@sp33dy ·
Nice tutorial! Thanks, will give this a play with shortly.
properties (22)
post_id39,627,327
authorsp33dy
permlinkre-clayjohn-learning-3d-graphics-with-three-js-or-advanced-materials-and-custom-shaders-20180320t160733846z
categoryutopian-io
json_metadata"{"app": "steemit/0.1", "tags": ["utopian-io"]}"
created2018-03-20 16:07:36
last_update2018-03-20 16:07:36
depth1
children0
net_rshares0
last_payout2018-03-27 16:07:36
cashout_time1969-12-31 23:59:59
total_payout_value0.000 SBD
curator_payout_value0.000 SBD
pending_payout_value0.000 SBD
promoted0.000 SBD
body_length58
author_reputation3,476,250,874,387
root_title"Learning 3D Graphics With Three.js | Advanced Materials and Custom Shaders"
beneficiaries[]
max_accepted_payout1,000,000.000 SBD
percent_steem_dollars10,000
@steemitboard ·
Congratulations @clayjohn! You have completed some achievement on Steemit and have been rewarded with new badge(s) :

[![](https://steemitimages.com/70x80/http://steemitboard.com/notifications/firstcommented.png)](http://steemitboard.com/@clayjohn) You got a First Reply

Click on any badge to view your own Board of Honor on SteemitBoard.
For more information about SteemitBoard, click [here](https://steemit.com/@steemitboard)

If you no longer want to receive notifications, reply to this comment with the word `STOP`

> Upvote this notification to help all Steemit users. Learn why [here](https://steemit.com/steemitboard/@steemitboard/http-i-cubeupload-com-7ciqeo-png)!
properties (22)
post_id39,857,890
authorsteemitboard
permlinksteemitboard-notify-clayjohn-20180321t232111000z
categoryutopian-io
json_metadata"{"image": ["https://steemitboard.com/img/notifications.png"]}"
created2018-03-21 23:21:09
last_update2018-03-21 23:21:09
depth1
children0
net_rshares0
last_payout2018-03-28 23:21:09
cashout_time1969-12-31 23:59:59
total_payout_value0.000 SBD
curator_payout_value0.000 SBD
pending_payout_value0.000 SBD
promoted0.000 SBD
body_length674
author_reputation38,705,954,145,809
root_title"Learning 3D Graphics With Three.js | Advanced Materials and Custom Shaders"
beneficiaries[]
max_accepted_payout1,000,000.000 SBD
percent_steem_dollars10,000