Toon shading or Cel shading is a type of non-photorealistic rendering technique designed to make 3D computer graphics appear more cartoonish by using less shading color instead of a smooth gradient effect.
The image files used in this lesson can be downloaded from the file named gradientMaps.zip. Extract the gradientMaps.zip contents into the ./dist/client/img/ folder.
import*asTHREEfrom'three'import{OrbitControls}from'three/examples/jsm/controls/OrbitControls'importStatsfrom'three/examples/jsm/libs/stats.module'import{GUI}from'dat.gui'constscene=newTHREE.Scene()scene.add(newTHREE.AxesHelper(5))constlight=newTHREE.PointLight(0xffffff,500)light.position.set(10,10,10)scene.add(light)constcamera=newTHREE.PerspectiveCamera(75,window.innerWidth/window.innerHeight,0.1,1000)camera.position.z=3constrenderer=newTHREE.WebGLRenderer()renderer.setSize(window.innerWidth,window.innerHeight)document.body.appendChild(renderer.domElement)newOrbitControls(camera,renderer.domElement)constboxGeometry=newTHREE.BoxGeometry()constsphereGeometry=newTHREE.SphereGeometry()consticosahedronGeometry=newTHREE.IcosahedronGeometry(1,0)constplaneGeometry=newTHREE.PlaneGeometry()consttorusKnotGeometry=newTHREE.TorusKnotGeometry()constthreeTone=newTHREE.TextureLoader().load('img/threeTone.jpg')threeTone.minFilter=THREE.NearestFilterthreeTone.magFilter=THREE.NearestFilterconstfourTone=newTHREE.TextureLoader().load('img/fourTone.jpg')fourTone.minFilter=THREE.NearestFilterfourTone.magFilter=THREE.NearestFilterconstfiveTone=newTHREE.TextureLoader().load('img/fiveTone.jpg')fiveTone.minFilter=THREE.NearestFilterfiveTone.magFilter=THREE.NearestFilterconstmaterial:THREE.MeshToonMaterial=newTHREE.MeshToonMaterial()constcube=newTHREE.Mesh(boxGeometry,material)cube.position.x=5scene.add(cube)constsphere=newTHREE.Mesh(sphereGeometry,material)sphere.position.x=3scene.add(sphere)consticosahedron=newTHREE.Mesh(icosahedronGeometry,material)icosahedron.position.x=0scene.add(icosahedron)constplane=newTHREE.Mesh(planeGeometry,material)plane.position.x=-2scene.add(plane)consttorusKnot=newTHREE.Mesh(torusKnotGeometry,material)torusKnot.position.x=-5scene.add(torusKnot)window.addEventListener('resize',onWindowResize,false)functiononWindowResize(){camera.aspect=window.innerWidth/window.innerHeightcamera.updateProjectionMatrix()renderer.setSize(window.innerWidth,window.innerHeight)render()}conststats=newStats()document.body.appendChild(stats.dom)constoptions={side:{FrontSide:THREE.FrontSide,BackSide:THREE.BackSide,DoubleSide:THREE.DoubleSide,},gradientMap:{Default:null,threeTone:'threeTone',fourTone:'fourTone',fiveTone:'fiveTone',},}constgui=newGUI()constdata={lightColor:light.color.getHex(),color:material.color.getHex(),gradientMap:'threeTone',}material.gradientMap=threeToneconstlightFolder=gui.addFolder('THREE.Light')lightFolder.addColor(data,'lightColor').onChange(()=>{light.color.setHex(Number(data.lightColor.toString().replace('#','0x')))})lightFolder.add(light,'intensity',0,2000)constmaterialFolder=gui.addFolder('THREE.Material')materialFolder.add(material,'transparent').onChange(()=>(material.needsUpdate=true))materialFolder.add(material,'opacity',0,1,0.01)materialFolder.add(material,'depthTest')materialFolder.add(material,'depthWrite')materialFolder.add(material,'alphaTest',0,1,0.01).onChange(()=>updateMaterial())materialFolder.add(material,'visible')materialFolder.add(material,'side',options.side).onChange(()=>updateMaterial())//materialFolder.open()constmeshToonMaterialFolder=gui.addFolder('THREE.MeshToonMaterial')meshToonMaterialFolder.addColor(data,'color').onChange(()=>{material.color.setHex(Number(data.color.toString().replace('#','0x')))})//shininess, specular and flatShading no longer supported in MeshToonMaterialmeshToonMaterialFolder.add(data,'gradientMap',options.gradientMap).onChange(()=>updateMaterial())meshToonMaterialFolder.open()functionupdateMaterial(){material.side=Number(material.side)asTHREE.Sidematerial.gradientMap=eval(data.gradientMapasstring)material.needsUpdate=true}functionanimate(){requestAnimationFrame(animate)render()stats.update()}functionrender(){renderer.render(scene,camera)}animate()