Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. You can use the CSS from another Pen by using it's URL and the proper URL extention.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Details

Privacy

Go PRO Window blinds lowered to protect code. Code Editor with window blinds (raised) and a light blub turned on.

Keep it secret; keep it safe.

Private Pens are hidden everywhere on CodePen, except to you. You can still share them and other people can see them, they just can't find them through searching or browsing.

Upgrade to PRO

Behavior

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

Template

Make Template?

Templates are Pens that can be used to start other Pens quickly from the create menu. The new Pen will copy all the code and settings from the template and make a new Pen (that is not a fork). You can view all of your templates, or learn more in the documentation.

Template URL

Any Pen can act as a template (even if you don't flip the toggle above) with a special URL you can use yourself or share with others. Here's this Pen's template URL:

Screenshot

Screenshot or Custom Thumbnail

Screenshots of Pens are shown in mobile browsers, RSS feeds, to users who chose images instead of iframes, and in social media sharing.

This Pen is using the default Screenshot, generated by CodePen. Upgrade to PRO to upload your own thumbnail that will be displayed on previews of this pen throughout the site and when sharing to social media.

Upgrade to PRO

HTML

              
                <head>
	<canvas id="canvas"></canvas>
</head>
<body>
</body>

              
            
!

CSS

              
                body {
    background-color: #000;    
    margin: 0;
		overflow: hidden;
}
              
            
!

JS

              
                //Shadow mapping using three.js shaderMaterial
//FF gives the error:Error: WebGL warning: drawElements: Texture level 0 would be read by TEXTURE_2D unit 0, but written by framebuffer attachment DEPTH_ATTACHMENT, which would be illegal feedback.
//Chrome produces artifacts until camera helper is added to the scene, then even when it is removed, the scene is rendered correctly
var canvas = document.getElementById("canvas");

var textureSize = 1024;
var centre = new THREE.Vector3(0,0,0);
var lightPosition = new THREE.Vector3(-80,80,80);
//Show cameraHelper?
var show_helper = false;

//Dat.gui library controls
var gui = new dat.GUI();
gui.add(this, 'show_helper').onChange(function(value){show_helper = value;});

//Initialise three.js
var scene = new THREE.Scene();
var renderer = new THREE.WebGLRenderer({antialias: true, canvas: canvas});
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( 0xaaaaaa, 1);

//Camera
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 2000);
camera.position.set(0,35,30);
scene.add(camera);
//Visualise camera frustum 
var cameraHelper = new THREE.CameraHelper(camera);

window.addEventListener( 'resize', onWindowResize, false );
function onWindowResize(){
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize( window.innerWidth, window.innerHeight );
}

//OrbitControls.js for camera manipulation
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.target = new THREE.Vector3(0,20,0);
controls.update();

//----------LIGHTING----------//
var vertexSource = `
precision mediump float;

uniform mat4 lightViewMatrix;
uniform mat4 lightProjectionMatrix;
varying vec3 vNormal;
varying vec3 vPosition;
varying vec4 lightSpaceVPosition;
varying vec2 textureCoord;

void main() {
  //Position of vertex on the screen
  gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0 );
  vNormal = normal;

  //Position of vertex in the world
  vPosition = vec3(modelMatrix * vec4(position, 1.0));
  //Position of vertex from the point of view of the light (for shadow testing)
  lightSpaceVPosition = vec4(lightProjectionMatrix * lightViewMatrix * vec4(vPosition, 1.0));

  //UV for texture (passed by Three.js)
  textureCoord = uv;
}`;

var fragmentSource = `
precision mediump float;

//Calculated depth map from the point of view of the light
uniform sampler2D shadowMap;
uniform vec3 lightPosition;

//Passed by vertex shader
varying vec3 vNormal;
varying vec3 vPosition;
varying vec4 lightSpaceVPosition;
varying vec2 textureCoord;

//Shadow camera extent
float near = 1.0; 
float far = 400.0; 

//https://learnopengl.com/Advanced-OpenGL/Depth-testing
float LinearizeDepth(float depth) {
 float z = depth * 2.0 - 1.0; // back to NDC 
 return (2.0 * near * far) / (far + near - z * (far - near));	
}

float ShadowCalculation(vec4 fragPosLightSpace, vec3 lightDirection, vec3 normal){
 //Perform perspective divide
 vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
 //Transform to [0,1] range
 projCoords = projCoords * 0.5 + 0.5;
 //Get closest depth value from light's perspective (using [0,1] range lightSpaceVPosition as coordinates)
 float closestDepth = texture2D(shadowMap, projCoords.xy).r; 
 //Get depth of current fragment from light's perspective
 float currentDepth = projCoords.z;
 //Use bias to remove line artifacts
 float bias = max(0.01 * (1.0 - dot(normal, lightDirection)), 0.005);
 //Check whether current fragment is in shadow
 float shadow = currentDepth - bias > closestDepth  ? 1.0 : 0.0;  

 //Cut off at the top to make everything outside the shadow camera's view be lit
 if(projCoords.z > 0.65){
  shadow = 0.0;
 }
 return shadow;
} 

void main() {

  vec3 normal = normalize(vNormal);
  vec3 lightDirection = normalize(lightPosition); 

  vec3 ambient = vec3(0.4,0.4,0.4);

  //How much a fragment faces the light
  float diff = max(dot(normal, lightDirection), 0.0);
  vec3 diffuse = diff * vec3(0.5,0.5,0.5);

  float shadow = ShadowCalculation(lightSpaceVPosition, lightDirection, normal);
  vec3 result =  ambient + (1.0-shadow) * diffuse;

  gl_FragColor = vec4(result, 1.0); 
}`;


//Target where shadows are rendered
//https://github.com/mrdoob/three.js/blob/master/examples/webgl_depth_texture.html
var shadowTarget = new THREE.WebGLRenderTarget(textureSize, textureSize);
shadowTarget.depthBuffer = true;
shadowTarget.depthTexture = new THREE.DepthTexture();

//Define the material, specifying attributes, uniforms, shaders etc.
var material = new THREE.ShaderMaterial( {
  uniforms: {
    lightPosition: { value: lightPosition },
    lightViewMatrix: {value: new THREE.Matrix4()},
    lightProjectionMatrix: {value: new THREE.Matrix4()},
    shadowMap: {value: shadowTarget.depthTexture}
  },
  vertexShader: vertexSource,
  fragmentShader: fragmentSource,
} );


var geo = new THREE.TorusKnotBufferGeometry(10, 3, 100, 16);
geo.translate(0,20,0);
var mesh = new THREE.Mesh(geo, material);
scene.add(mesh);

var floor_geometry = new THREE.PlaneBufferGeometry(1000,1000,2,2);
floor_geometry.lookAt(new THREE.Vector3(0,1,0));
var floor = new THREE.Mesh(floor_geometry, material);
scene.add(floor);

//Shadow camera and geometry
var shadowCamera = new THREE.OrthographicCamera(-100, 100, 100, -100, 1, 400);
shadowCamera.position.set(-80, 80, 80);
shadowCamera.lookAt(centre);

scene.add(shadowCamera);

material.uniforms.lightPosition.value = lightPosition;
material.uniforms.lightViewMatrix.value = shadowCamera.matrixWorldInverse;
material.uniforms.lightProjectionMatrix.value = shadowCamera.projectionMatrix;

//----------DRAW----------//
function draw(){

  controls.update();
  
  //Render depth values from light to shadow texture
  renderer.setRenderTarget(shadowTarget);
  renderer.render(scene, shadowCamera);
  
  if(show_helper){
    //Triggers correct scene
    scene.add(cameraHelper);
  }
  //Render main scene
  renderer.setRenderTarget(null);  
  renderer.render(scene, camera);
  
  if(show_helper){
    //Correct scene even when disabled
    scene.remove(cameraHelper);
  }

  requestAnimationFrame(draw);
}

requestAnimationFrame(draw);
              
            
!
999px
We're stronger <u>nited than <div>ided.

Console