Skip to content

Instantly share code, notes, and snippets.

@duhaime
Last active July 29, 2024 01:24
Show Gist options
  • Save duhaime/60c7083009bbd49ce50a58c371d8c818 to your computer and use it in GitHub Desktop.
Save duhaime/60c7083009bbd49ce50a58c371d8c818 to your computer and use it in GitHub Desktop.
Using canvas textures in three.js
<html>
<head>
<style>
html, body { width: 100%; height: 100%; background: #000; }
body { margin: 0; overflow: hidden; }
canvas { width: 100%; height: 100%; }
</style>
</head>
<body>
<script src='https://cdnjs.cloudflare.com/ajax/libs/three.js/88/three.min.js'></script>
<script src='TrackballControls.js'></script>
<script>
/**
* Generate scene object with a background color
**/
function getScene() {
var scene = new THREE.Scene();
scene.background = new THREE.Color(0x111111);
return scene;
}
/**
* Generate the camera to be used in the scene. Camera args:
* [0] field of view: identifies the portion of the scene
* visible at any time (in degrees)
* [1] aspect ratio: identifies the aspect ratio of the
* scene in width/height
* [2] near clipping plane: objects closer than the near
* clipping plane are culled from the scene
* [3] far clipping plane: objects farther than the far
* clipping plane are culled from the scene
**/
function getCamera() {
var aspectRatio = window.innerWidth / window.innerHeight;
var camera = new THREE.PerspectiveCamera(75, aspectRatio, 0.1, 1000);
camera.position.set(0, 1, 5);
return camera;
}
/**
* Generate the light to be used in the scene. Light args:
* [0]: Hexadecimal color of the light
* [1]: Numeric value of the light's strength/intensity
* [2]: The distance from the light where the intensity is 0
* @param {obj} scene: the current scene object
**/
function getLight(scene) {
var light = new THREE.PointLight(0xffffff, 1, 0);
light.position.set(1, 1, 1);
scene.add(light);
var ambientLight = new THREE.AmbientLight(0x111111);
scene.add(ambientLight);
return light;
}
/**
* Generate the renderer to be used in the scene
**/
function getRenderer() {
// Create the canvas with a renderer
var renderer = new THREE.WebGLRenderer({antialias: false});
// Add support for retina displays
renderer.setPixelRatio(window.devicePixelRatio);
// Specify the size of the canvas
renderer.setSize(window.innerWidth, window.innerHeight);
// Add the canvas to the DOM
document.body.appendChild(renderer.domElement);
return renderer;
}
/**
* Generate the controls to be used in the scene
* @param {obj} camera: the three.js camera for the scene
* @param {obj} renderer: the three.js renderer for the scene
**/
function getControls(camera, renderer) {
var controls = new THREE.TrackballControls(camera, renderer.domElement);
controls.zoomSpeed = 0.4;
controls.panSpeed = 0.4;
return controls;
}
/**
* Create retina quality canvas
**/
var PIXEL_RATIO = (function () {
var ctx = document.createElement('canvas').getContext('2d'),
dpr = window.devicePixelRatio || 1,
bsr = ctx.webkitBackingStorePixelRatio ||
ctx.mozBackingStorePixelRatio ||
ctx.msBackingStorePixelRatio ||
ctx.oBackingStorePixelRatio ||
ctx.backingStorePixelRatio || 1;
return dpr / bsr;
})();
createRetinaCanvas = function(w, h, ratio) {
if (!ratio) { ratio = PIXEL_RATIO; }
var can = document.createElement('canvas');
can.width = w * ratio;
can.height = h * ratio;
can.style.width = w + 'px';
can.style.height = h + 'px';
can.getContext('2d').setTransform(ratio, 0, 0, ratio, 0, 0);
return can;
}
function addTexture() {
var text = 'cats'
//create image
var bitmap = createRetinaCanvas(100, 100);
var ctx = bitmap.getContext('2d', {antialias: false});
ctx.font = 'Bold 20px Arial';
ctx.beginPath();
ctx.rect(0, 0, 100, 100);
ctx.fillStyle = 'red';
ctx.fill();
ctx.fillStyle = 'white';
ctx.fillText(text, 0, 20);
ctx.strokeStyle = 'black';
ctx.strokeText(text, 0, 20);
// canvas contents will be used for a texture
var texture = new THREE.Texture(bitmap)
texture.needsUpdate = true;
var material = new THREE.MeshBasicMaterial({ map: texture });
var geometry = new THREE.BoxGeometry( 1, 1, 1 );
cube = new THREE.Mesh(geometry, material);
scene.add(cube)
}
// Render loop
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
controls.update();
cube.rotation.y += 0.01;
cube.rotation.z += 0.01;
};
var scene = getScene();
var camera = getCamera();
var light = getLight(scene);
var renderer = getRenderer();
var controls = getControls(camera, renderer);
var cube;
addTexture()
render();
</script>
</body>
</html>
THREE.TrackballControls=function(e,t){var o=this,n={NONE:-1,ROTATE:0,ZOOM:1,PAN:2,TOUCH_ROTATE:3,TOUCH_ZOOM_PAN:4};this.object=e,this.domElement=void 0!==t?t:document,this.enabled=!0,this.screen={left:0,top:0,width:0,height:0},this.rotateSpeed=1,this.zoomSpeed=1.2,this.panSpeed=.3,this.noRotate=!1,this.noZoom=!1,this.noPan=!1,this.staticMoving=!1,this.dynamicDampingFactor=.2,this.minDistance=0,this.maxDistance=1/0,this.keys=[65,83,68],this.target=new THREE.Vector3;var s=new THREE.Vector3,c=n.NONE,a=n.NONE,i=new THREE.Vector3,r=new THREE.Vector2,p=new THREE.Vector2,h=new THREE.Vector3,d=0,u=new THREE.Vector2,E=new THREE.Vector2,m=0,l=0,g=new THREE.Vector2,y=new THREE.Vector2;this.target0=this.target.clone(),this.position0=this.object.position.clone(),this.up0=this.object.up.clone();var v={type:"change"},w={type:"start"},T={type:"end"};this.handleResize=function(){if(this.domElement===document)this.screen.left=0,this.screen.top=0,this.screen.width=window.innerWidth,this.screen.height=window.innerHeight;else{var e=this.domElement.getBoundingClientRect(),t=this.domElement.ownerDocument.documentElement;this.screen.left=e.left+window.pageXOffset-t.clientLeft,this.screen.top=e.top+window.pageYOffset-t.clientTop,this.screen.width=e.width,this.screen.height=e.height}};var b,f,O,R,H,L,V,k,N,j,D,A,Y=(b=new THREE.Vector2,function(e,t){return b.set((e-o.screen.left)/o.screen.width,(t-o.screen.top)/o.screen.height),b}),C=(f=new THREE.Vector2,function(e,t){return f.set((e-.5*o.screen.width-o.screen.left)/(.5*o.screen.width),(o.screen.height+2*(o.screen.top-t))/o.screen.width),f});function P(e){!1!==o.enabled&&(window.removeEventListener("keydown",P),a=c,c===n.NONE&&(e.keyCode!==o.keys[n.ROTATE]||o.noRotate?e.keyCode!==o.keys[n.ZOOM]||o.noZoom?e.keyCode!==o.keys[n.PAN]||o.noPan||(c=n.PAN):c=n.ZOOM:c=n.ROTATE))}function X(e){!1!==o.enabled&&(c=a,window.addEventListener("keydown",P,!1))}function M(e){!1!==o.enabled&&(e.preventDefault(),e.stopPropagation(),c===n.NONE&&(c=e.button),c!==n.ROTATE||o.noRotate?c!==n.ZOOM||o.noZoom?c!==n.PAN||o.noPan||(g.copy(Y(e.pageX,e.pageY)),y.copy(g)):(u.copy(Y(e.pageX,e.pageY)),E.copy(u)):(p.copy(C(e.pageX,e.pageY)),r.copy(p)),document.addEventListener("mousemove",Z,!1),document.addEventListener("mouseup",S,!1),o.dispatchEvent(w))}function Z(e){!1!==o.enabled&&(e.preventDefault(),e.stopPropagation(),c!==n.ROTATE||o.noRotate?c!==n.ZOOM||o.noZoom?c!==n.PAN||o.noPan||y.copy(Y(e.pageX,e.pageY)):E.copy(Y(e.pageX,e.pageY)):(r.copy(p),p.copy(C(e.pageX,e.pageY))))}function S(e){!1!==o.enabled&&(e.preventDefault(),e.stopPropagation(),c=n.NONE,document.removeEventListener("mousemove",Z),document.removeEventListener("mouseup",S),o.dispatchEvent(T))}function x(e){if(!1!==o.enabled&&!0!==o.noZoom){switch(e.preventDefault(),e.stopPropagation(),e.deltaMode){case 2:u.y-=.025*e.deltaY;break;case 1:u.y-=.01*e.deltaY;break;default:u.y-=25e-5*e.deltaY}o.dispatchEvent(w),o.dispatchEvent(T)}}function z(e){if(!1!==o.enabled){switch(e.preventDefault(),e.touches.length){case 1:c=n.TOUCH_ROTATE,p.copy(C(e.touches[0].pageX,e.touches[0].pageY)),r.copy(p);break;default:c=n.TOUCH_ZOOM_PAN;var t=e.touches[0].pageX-e.touches[1].pageX,s=e.touches[0].pageY-e.touches[1].pageY;l=m=Math.sqrt(t*t+s*s);var a=(e.touches[0].pageX+e.touches[1].pageX)/2,i=(e.touches[0].pageY+e.touches[1].pageY)/2;g.copy(Y(a,i)),y.copy(g)}o.dispatchEvent(w)}}function _(e){if(!1!==o.enabled)switch(e.preventDefault(),e.stopPropagation(),e.touches.length){case 1:r.copy(p),p.copy(C(e.touches[0].pageX,e.touches[0].pageY));break;default:var t=e.touches[0].pageX-e.touches[1].pageX,n=e.touches[0].pageY-e.touches[1].pageY;l=Math.sqrt(t*t+n*n);var s=(e.touches[0].pageX+e.touches[1].pageX)/2,c=(e.touches[0].pageY+e.touches[1].pageY)/2;y.copy(Y(s,c))}}function q(e){if(!1!==o.enabled){switch(e.touches.length){case 0:c=n.NONE;break;case 1:c=n.TOUCH_ROTATE,p.copy(C(e.touches[0].pageX,e.touches[0].pageY)),r.copy(p)}o.dispatchEvent(T)}}function F(e){!1!==o.enabled&&e.preventDefault()}this.rotateCamera=(R=new THREE.Vector3,H=new THREE.Quaternion,L=new THREE.Vector3,V=new THREE.Vector3,k=new THREE.Vector3,N=new THREE.Vector3,function(){N.set(p.x-r.x,p.y-r.y,0),(O=N.length())?(i.copy(o.object.position).sub(o.target),L.copy(i).normalize(),V.copy(o.object.up).normalize(),k.crossVectors(V,L).normalize(),V.setLength(p.y-r.y),k.setLength(p.x-r.x),N.copy(V.add(k)),R.crossVectors(N,i).normalize(),O*=o.rotateSpeed,H.setFromAxisAngle(R,O),i.applyQuaternion(H),o.object.up.applyQuaternion(H),h.copy(R),d=O):!o.staticMoving&&d&&(d*=Math.sqrt(1-o.dynamicDampingFactor),i.copy(o.object.position).sub(o.target),H.setFromAxisAngle(h,d),i.applyQuaternion(H),o.object.up.applyQuaternion(H)),r.copy(p)}),this.zoomCamera=function(){var e;c===n.TOUCH_ZOOM_PAN?(e=m/l,m=l,i.multiplyScalar(e)):(1!==(e=1+(E.y-u.y)*o.zoomSpeed)&&e>0&&i.multiplyScalar(e),o.staticMoving?u.copy(E):u.y+=(E.y-u.y)*this.dynamicDampingFactor)},this.panCamera=(j=new THREE.Vector2,D=new THREE.Vector3,A=new THREE.Vector3,function(){j.copy(y).sub(g),j.lengthSq()&&(j.multiplyScalar(i.length()*o.panSpeed),A.copy(i).cross(o.object.up).setLength(j.x),A.add(D.copy(o.object.up).setLength(j.y)),o.object.position.add(A),o.target.add(A),o.staticMoving?g.copy(y):g.add(j.subVectors(y,g).multiplyScalar(o.dynamicDampingFactor)))}),this.checkDistances=function(){o.noZoom&&o.noPan||(i.lengthSq()>o.maxDistance*o.maxDistance&&(o.object.position.addVectors(o.target,i.setLength(o.maxDistance)),u.copy(E)),i.lengthSq()<o.minDistance*o.minDistance&&(o.object.position.addVectors(o.target,i.setLength(o.minDistance)),u.copy(E)))},this.update=function(){i.subVectors(o.object.position,o.target),o.noRotate||o.rotateCamera(),o.noZoom||o.zoomCamera(),o.noPan||o.panCamera(),o.object.position.addVectors(o.target,i),o.checkDistances(),o.object.lookAt(o.target),s.distanceToSquared(o.object.position)>1e-6&&(o.dispatchEvent(v),s.copy(o.object.position))},this.reset=function(){c=n.NONE,a=n.NONE,o.target.copy(o.target0),o.object.position.copy(o.position0),o.object.up.copy(o.up0),i.subVectors(o.object.position,o.target),o.object.lookAt(o.target),o.dispatchEvent(v),s.copy(o.object.position)},this.dispose=function(){this.domElement.removeEventListener("contextmenu",F,!1),this.domElement.removeEventListener("mousedown",M,!1),this.domElement.removeEventListener("wheel",x,!1),this.domElement.removeEventListener("touchstart",z,!1),this.domElement.removeEventListener("touchend",q,!1),this.domElement.removeEventListener("touchmove",_,!1),document.removeEventListener("mousemove",Z,!1),document.removeEventListener("mouseup",S,!1),window.removeEventListener("keydown",P,!1),window.removeEventListener("keyup",X,!1)},this.domElement.addEventListener("contextmenu",F,!1),this.domElement.addEventListener("mousedown",M,!1),this.domElement.addEventListener("wheel",x,!1),this.domElement.addEventListener("touchstart",z,!1),this.domElement.addEventListener("touchend",q,!1),this.domElement.addEventListener("touchmove",_,!1),window.addEventListener("keydown",P,!1),window.addEventListener("keyup",X,!1),this.handleResize(),this.update()},THREE.TrackballControls.prototype=Object.create(THREE.EventDispatcher.prototype),THREE.TrackballControls.prototype.constructor=THREE.TrackballControls;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment