ShaderMaterial Tangent Space

by Matt

CSS

html,
body,
canvas {
  margin: 0;
  padding: 0;
  width: 100%;
  height: 100%;
  display: block;
}

JavaScript

import * as THREE from '//cdn.skypack.dev/[email protected]'
import { OrbitControls } from '//cdn.skypack.dev/[email protected]/examples/jsm/controls/OrbitControls.js'

// Scene, Camera
const scene = new THREE.Scene()
scene.background = new THREE.Color('black')
const camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
)
camera.position.set(0, 2, 3)

// WebGL renderer
const renderer = new THREE.WebGLRenderer({ antialias: true })
renderer.setSize(window.innerWidth, window.innerHeight)
document.body.appendChild(renderer.domElement)

// OrbitControls
const controls = new OrbitControls(camera, renderer.domElement)
controls.autoRotate = true

// Mesh
const geometry = new THREE.SphereGeometry(1, 32, 32)
const material = new THREE.ShaderMaterial({
	vertexShader: `
  	attribute vec4 tangent;
    
    varying vec3 vTangent;
  	
    void main() {
    	vTangent = tangent.xyz;
	    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
  `,
  fragmentShader: `
    varying vec3 vTangent;
    
  	void main() {
    	vec3 rgb = normalize(vTangent);
      rgb = rgb * 0.5 + 0.5;
	    gl_FragColor = vec4(rgb, 1.);
    }
	`
})
geometry.computeTangents()

const mesh = new THREE.Mesh(geometry, material)
scene.add(mesh)

const axes = new THREE.AxesHelper(5)
scene.add(axes)


// Render loop
function animate() {
  requestAnimationFrame(animate)
  controls.update()
  renderer.render(scene, camera)
}
animate()

// Window sizing
window.addEventListener('resize', onWindowResize, false)
function onWindowResize() {
  camera.aspect = window.innerWidth / window.innerHeight
  camera.updateProjectionMatrix()

  renderer.setSize(window.innerWidth, window.innerHeight)
}