Parcourir la source

AsciiRenderer

zz85 il y a 13 ans
Parent
commit
202bf85a22

+ 188 - 0
examples/canvas_ascii_effect.html

@@ -0,0 +1,188 @@
+<!doctype html>
+<html lang="en">
+
+	<head>
+		<title>three.js ASCII - geometry - cube</title>
+		<meta charset="utf-8">
+		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+		<style>
+			body {
+				font-family: Monospace;
+				background-color: #f0f0f0;
+				margin: 0px;
+				overflow: hidden; 
+			}
+		</style>
+	</head>
+	<body>
+
+		<script src="../build/Three.js"></script>
+		<script src="js/Stats.js"></script>
+		<script src="js/renderers/AsciiRenderer.js"></script>
+		<script>
+		// Just swap out the default CanvasRenderer -> AsciiRenderer and things should work
+		// Let's start with the class spinning cube example from three.js
+
+		var container, stats;
+
+		var camera, scene, renderer;
+
+
+		var cube, plane;
+
+		var targetYRotation = targetXRotation = 0;
+		var targetYRotationOnMouseDown = targetXRotationOnMouseDown = 0;
+
+		var mouseX = 0, mouseY = 0;
+
+		var mouseYOnMouseDown = mouseXOnMouseDown = 0;
+		var windowHalfX = window.innerWidth / 2;
+		var windowHalfY = window.innerHeight / 2;
+
+
+		init();
+		animate();
+
+		function init() {
+
+			container = document.createElement( 'div' );
+			document.body.appendChild( container );
+
+			var info = document.createElement( 'div' );
+			info.style.position = 'absolute';
+			info.style.top = '10px';
+			info.style.width = '100%';
+			info.style.textAlign = 'center';
+			info.innerHTML = 'Drag to spin the cube';
+			container.appendChild( info );
+
+			scene = new THREE.Scene();
+
+			camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 );
+			camera.position.y = 150;
+			camera.position.z = 500;
+			scene.add( camera );
+
+			// Cube
+
+			var materials = [];
+
+			for ( var i = 0; i < 6; i ++ ) {
+
+				materials.push( new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff } ) );
+
+			}
+
+			cube = new THREE.Mesh( new THREE.CubeGeometry( 200, 200, 200, 1, 1, 1, materials ), new THREE.MeshFaceMaterial() );
+			cube.position.y = 150;
+			scene.add( cube );
+
+			// Plane
+
+			plane = new THREE.Mesh( new THREE.PlaneGeometry( 400, 400 ), new THREE.MeshBasicMaterial( { color: 0xe0e0e0 } ) );
+			scene.add( plane );
+
+			renderer = new THREE.ASCIIRenderer(); //THREE.CanvasRenderer
+			renderer.setSize( window.innerWidth, window.innerHeight );
+		  
+
+			container.appendChild( renderer.domElement );
+
+			stats = new Stats();
+			stats.domElement.style.position = 'absolute';
+			stats.domElement.style.top = '0px';
+			container.appendChild( stats.domElement );
+
+			document.addEventListener( 'mousedown', onDocumentMouseDown, false );
+			document.addEventListener( 'touchstart', onDocumentTouchStart, false );
+			document.addEventListener( 'touchmove', onDocumentTouchMove, false );
+		}
+
+		//
+
+		function onDocumentMouseDown( event ) {
+
+			event.preventDefault();
+		   
+		  
+			document.addEventListener( 'mousemove', onDocumentMouseMove, false );
+			document.addEventListener( 'mouseup', onDocumentMouseUp, false );
+			document.addEventListener( 'mouseout', onDocumentMouseOut, false );
+
+			mouseXOnMouseDown = event.clientX - windowHalfX;
+			mouseYOnMouseDown = event.clientY - windowHalfY;
+			targetYRotationOnMouseDown = targetYRotation;
+			targetXRotationOnMouseDown = targetXRotation;
+		}
+
+		function onDocumentMouseMove( event ) {
+
+			mouseX = event.clientX - windowHalfX;
+
+			targetYRotation = targetYRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.02;
+			targetXRotation = targetXRotationOnMouseDown + ( mouseY - mouseYOnMouseDown ) * 0.02;
+		}
+
+		function onDocumentMouseUp( event ) {
+
+			document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
+			document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
+			document.removeEventListener( 'mouseout', onDocumentMouseOut, false );
+		}
+
+		function onDocumentMouseOut( event ) {
+
+			document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
+			document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
+			document.removeEventListener( 'mouseout', onDocumentMouseOut, false );
+		}
+
+		function onDocumentTouchStart( event ) {
+
+			if ( event.touches.length == 1 ) {
+
+				event.preventDefault();
+
+				mouseXOnMouseDown = event.touches[ 0 ].pageX - windowHalfX;
+				targetRotationOnMouseDown = targetRotation;
+			}
+		}
+
+		function onDocumentTouchMove( event ) {
+
+			if ( event.touches.length == 1 ) {
+
+				event.preventDefault();
+
+				mouseX = event.touches[ 0 ].pageX - windowHalfX;
+				targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.05;;
+			}
+		}
+
+		//
+
+		function animate() {
+
+			requestAnimationFrame( animate );
+
+			render();
+			stats.update();
+
+		}
+
+		function render() {
+
+			cube.rotation.x += ( targetXRotation - cube.rotation.x ) * 0.05;
+			plane.rotation.y  = cube.rotation.y += ( targetYRotation - cube.rotation.y ) * 0.05;
+			
+			
+			renderer.render( scene, camera );
+		 
+
+
+		}
+
+
+		</script>
+</body>
+</html>

+ 244 - 0
examples/js/renderers/AsciiRenderer.js

@@ -0,0 +1,244 @@
+/*
+ * @author zz85 / https://github.com/zz85 
+ *
+ * Usage: Just replace your CanvasRenderer / WebGLRenderer with AsciiRenderer. The rest is magic.
+ *
+ * Ascii generation is based on http://www.nihilogic.dk/labs/jsascii/
+ * Maybe more about this later with a blog post at http://lab4games.net/zz85/blog
+ * 
+ * 16 April 2012 - @blurspline
+ */
+  
+THREE.ASCIIRenderer = function( renderer, charSet, options ) {
+
+
+	// its fun to create one your own!
+	charSet = (charSet === undefined) ? ' .:-=+*#%@' : charSet; 
+	
+	// ' .,:;=|iI+hHOE#`$'; 
+	// darker bolder character set from https://github.com/saw/Canvas-ASCII-Art/
+	// ' .\'`^",:;Il!i~+_-?][}{1)(|/tfjrxnuvczXYUJCLQ0OZmwqpdbkhao*#MW&8%B@$'.split('');
+
+	if (!options) options = {};
+	// Some ASCII settings
+	var bResolution = !options['resolution'] ? 0.15 : options['resolution']; // Higher for more details
+	var iScale = !options['scale'] ? 1 : options['scale'];
+	var bColor = !options['color'] ? false : options['color']; // nice but slows down rendering!
+	var bAlpha = !options['alpha'] ? false : options['alpha']; // Transparency
+	var bBlock = !options['block'] ? false : options['block']; // blocked characters. like good O dos
+	var bInvert = !options['invert'] ? false : options['invert']; // black is white, white is black
+	
+	var strResolution = 'low';
+
+	renderer = (renderer === undefined) ? THREE.CanvasRenderer : renderer; //THREE.WebGLRenderer 
+	var canvasRenderer = new renderer();
+	var width, height;
+
+	var domElement = document.createElement('div');
+	var oAscii = document.createElement("table");
+	domElement.appendChild(oAscii);
+
+	var iWidth, iHeight;
+	var oImg;
+
+	this.setSize = function(w, h) {
+		width = w;
+		height = h;
+		canvasRenderer.setSize( w, h );
+
+		initAsciiSize();
+
+	};
+
+
+	this.render = function() {
+		canvasRenderer.render.apply(canvasRenderer, arguments);
+		asciifyImage(canvasRenderer, oAscii);
+	};
+
+	this.domElement = domElement;
+
+
+	// Throw in ascii library from http://www.nihilogic.dk/labs/jsascii/jsascii.js
+	/*
+	* jsAscii 0.1
+	* Copyright (c) 2008 Jacob Seidelin, [email protected], http://blog.nihilogic.dk/
+	* MIT License [http://www.nihilogic.dk/licenses/mit-license.txt]
+	*/
+
+	function initAsciiSize() {
+		iWidth = Math.round(width * fResolution);
+		iHeight = Math.round(height * fResolution);
+
+		oCanvas.width = iWidth;
+		oCanvas.height = iHeight;
+		// oCanvas.style.display = "none";
+		// oCanvas.style.width = iWidth;
+		// oCanvas.style.height = iHeight;
+
+		oImg = canvasRenderer.domElement;
+		if (oImg.style.backgroundColor) {
+			oAscii.rows[0].cells[0].style.backgroundColor = oImg.style.backgroundColor;
+			oAscii.rows[0].cells[0].style.color = oImg.style.color;
+		}
+
+		oAscii.cellSpacing = 0;
+		oAscii.cellPadding = 0;
+
+		var oStyle = oAscii.style;
+		oStyle.display = "inline";
+		oStyle.width = Math.round(iWidth/fResolution*iScale) + "px";
+		oStyle.height = Math.round(iHeight/fResolution*iScale) + "px";
+		oStyle.whiteSpace = "pre";
+		oStyle.margin = "0px";
+		oStyle.padding = "0px";
+		oStyle.letterSpacing = fLetterSpacing + "px";
+		oStyle.fontFamily = strFont;
+		oStyle.fontSize = fFontSize + "px";
+		oStyle.lineHeight = fLineHeight + "px";
+		oStyle.textAlign = "left";
+		oStyle.textDecoration = "none";
+	}
+
+
+	var aDefaultCharList = (" .,:;i1tfLCG08@").split("");
+	var aDefaultColorCharList = (" CGO08@").split("");
+	var strFont = "courier new, monospace";
+
+	var oCanvasImg = canvasRenderer.domElement;
+
+	var oCanvas = document.createElement("canvas");
+	if (!oCanvas.getContext) {
+		return;
+	}
+	var oCtx = oCanvas.getContext("2d");
+	if (!oCtx.getImageData) {
+		return;
+	}
+
+	var aCharList = (bColor ? aDefaultColorCharList : aDefaultCharList);
+
+	if (charSet) aCharList = charSet; 
+
+	var fResolution = 0.5;
+	switch (strResolution) {
+		case "low" : 	fResolution = 0.25; break;
+		case "medium" : fResolution = 0.5; break;
+		case "high" : 	fResolution = 1; break;
+	}
+
+	if (bResolution) fResolution = bResolution;
+
+	// Setup dom
+	var fFontSize = (2/fResolution)*iScale;
+	var fLineHeight = (2/fResolution)*iScale;
+
+	// adjust letter-spacing for all combinations of scale and resolution to get it to fit the image width.
+	var fLetterSpacing = 0;
+	if (strResolution == "low") {
+		switch (iScale) {
+			case 1 : fLetterSpacing = -1; break;
+			case 2 : 
+			case 3 : fLetterSpacing = -2.1; break;
+			case 4 : fLetterSpacing = -3.1; break;
+			case 5 : fLetterSpacing = -4.15; break;
+		}
+	}
+	if (strResolution == "medium") {
+		switch (iScale) {
+			case 1 : fLetterSpacing = 0; break;
+			case 2 : fLetterSpacing = -1; break;
+			case 3 : fLetterSpacing = -1.04; break;
+			case 4 : 
+			case 5 : fLetterSpacing = -2.1; break;
+		}
+	}
+	if (strResolution == "high") {
+		switch (iScale) {
+			case 1 : 
+			case 2 : fLetterSpacing = 0; break;
+			case 3 : 
+			case 4 : 
+			case 5 : fLetterSpacing = -1; break;
+		}
+	}
+
+
+	// can't get a span or div to flow like an img element, but a table works?
+
+
+	// convert img element to ascii
+	function asciifyImage(canvasRenderer, oAscii) 
+	{
+
+		oCtx.clearRect(0, 0, iWidth, iHeight);
+		oCtx.drawImage(oCanvasImg, 0, 0, iWidth, iHeight);
+		var oImgData = oCtx.getImageData(0, 0, iWidth, iHeight).data;
+
+		// Coloring loop starts now
+		var strChars = "";
+
+		// console.time('rendering');
+
+		for (var y=0;y<iHeight;y+=2) {
+			for (var x=0;x<iWidth;x++) {
+				var iOffset = (y*iWidth + x) * 4;
+	
+				var iRed = oImgData[iOffset];
+				var iGreen = oImgData[iOffset + 1];
+				var iBlue = oImgData[iOffset + 2];
+				var iAlpha = oImgData[iOffset + 3];
+				var iCharIdx;
+
+				var fBrightness;
+			  
+				fBrightness = (0.3*iRed + 0.59*iGreen + 0.11*iBlue) / 255;
+				// fBrightness = (0.3*iRed + 0.5*iGreen + 0.3*iBlue) / 255;
+				
+				if (iAlpha == 0) {
+  					// should calculate alpha instead, but quick hack :)
+					//fBrightness *= (iAlpha / 255); 
+					fBrightness = 1;
+					
+				} 
+							 
+				iCharIdx = Math.floor((1-fBrightness) * (aCharList.length-1));
+
+				if (bInvert) {
+					iCharIdx = aCharList.length - iCharIdx - 1;
+				}
+			  
+				// good for debugging
+				//fBrightness = Math.floor(fBrightness * 10);
+				//strThisChar = fBrightness;
+			  
+				var strThisChar = aCharList[iCharIdx];		
+			  
+				if (strThisChar===undefined || strThisChar == " ") 
+					strThisChar = "&nbsp;";
+			  
+				if (bColor) {
+					strChars += "<span style='"
+						+ "color:rgb("+iRed+","+iGreen+","+iBlue+");"
+						+ (bBlock ? "background-color:rgb("+iRed+","+iGreen+","+iBlue+");" : "")
+						+ (bAlpha ? "opacity:" + (iAlpha/255) + ";" : "")
+						+ "'>" + strThisChar + "</span>";
+				} else {
+					strChars += strThisChar;
+				}
+			}
+			strChars += "<br/>";
+		}
+	
+		oAscii.innerHTML = "<tr><td>" + strChars + "</td></tr>";
+
+		// console.timeEnd('rendering');
+		
+		// return oAscii;
+	}
+
+
+	// end modified asciifyImage block
+
+	
+};

+ 7 - 7
src/extras/geometries/ParametricGeometries.js

@@ -22,7 +22,7 @@ THREE.ParametricGeometries = {
 			x = 3 * cos(u) * (1 + sin(u)) + (2 * (1 - cos(u) / 2)) * cos(v + pi);
 			z = -8 * sin(u);
 		}
-	  
+
 		y = -2 * (1 - cos(u) / 2) * sin(v);
 		
 		return new THREE.Vector3(x, y, z);
@@ -32,7 +32,7 @@ THREE.ParametricGeometries = {
 		
 		return function(u, v) {
 			var x = u * width;
-			var y = 0; 
+			var y = 0;
 			var z = v * height;
 
 			console.log(x, y, z);
@@ -64,8 +64,8 @@ THREE.ParametricGeometries = {
 		u *= pi;
 		t *= 2 * pi;
 
-		u = u * 2
-		var phi = u / 2
+		u = u * 2;
+		var phi = u / 2;
 		var major = 2.25, a = 0.125, b = 0.65;
 		var x, y, z;
 		x = a * cos(t) * cos(phi) - b * sin(t) * sin(phi);
@@ -173,7 +173,7 @@ THREE.TubeGeometry2.prototype.constructor = THREE.TubeGeometry2;
 			t *= Math.PI * 2;
 
 			var r = 0.5;
-		  
+
 			var tx = (1 + r * Math.cos(q * t)) * Math.cos(p * t),
 				ty = (1 + r * Math.cos(q * t)) * Math.sin(p * t),
 				tz = r * Math.sin(q * t);
@@ -187,7 +187,7 @@ THREE.TubeGeometry2.prototype.constructor = THREE.TubeGeometry2;
 	var radiusSegments = segmentsT;
 	var extrudePath = new TorusKnotCurve();
 
-	 THREE.TubeGeometry2.call( this, extrudePath, segments, tube, radiusSegments, true, false );
+	THREE.TubeGeometry2.call( this, extrudePath, segments, tube, radiusSegments, true, false );
 
 
 };
@@ -222,7 +222,7 @@ THREE.PlaneGeometry2 = function(width, depth, segmentsWidth, segmentsDepth) {
 	function plane(u, v) {
 		
 		var x = u * width;
-		var y = 0; 
+		var y = 0;
 		var z = v * depth;
 
 		return new THREE.Vector3(x, y, z);