tech explorers, welcome!

Etiqueta: modelos 3d

Soporte para mando PS5

Simplicidad en su máxima expresión.

Hoy comparto este simple pero efectivo y elegante soporte para mando de PS5.

Algunas imágenes/diseños de concepto:

Se sostiene por sí solo sin tornillos ni pegamento. Se cuelga directamente del lateral de la PS5 y es expandible por diseño (probablemente quepan hasta 4 mandos en cada lado).

Algunas fotos reales:

Y, por último, los .stl listos para imprimir:

https://theroamingworkshop.cloud/demos/PS5-DualSense-Holder-A_v1.stl

https://theroamingworkshop.cloud/demos/PS5-DualSense-Holder-B_v1.stl

🎅 Feliz Navidad! 🎁

También disponible en Cults3D como descarga gratuita 💌

Batman con su pistola gancho colgando de tu salón

La verdad es que imprimir con resina es otro nivel. A pesar de las complicaciones de la limpieza, el resultado es realmente increíble, y hoy te enseño mi primera impresión con la Anycubic Photon Mono X2: un Batman para colgar de tu salón con su pistola gancho.

Modelos

La impresión que ves consta de dos modelos gratuitos. Por ello, mi enorme agradecimiento a los autores y mi referencia a su trabajo:

Lo único que he hecho yo es añadirle un esqueleto al modelo y darle la postura deseada, uniéndole luego la pistola a la mano. Asique aquí tienes mi modelo para que lo puedas imprimir tal y como se muestra en las imágenes.

Vista previa

Extras

Para completar el modelo, deberás crearle una capa y un gancho o pinza con el cual colgarlo.

Capa

Para la capa yo he recortado un trozo de tela de una prenda de deporte antigua. Solemos tener prendas de este estilo en color negro y suelen tener también una buena textura y brillo que dan el pego.

Empieza cortando un rectángulo y luego dale forma.

En la parte superior, enrolla un alambre o un clip que te permita ajustar la capa alrededor del cuello de la figura.

Gancho

Simplemente busca un enganche que te venga bien para colgarlo. Yo he usado una pinza a la cual he atado un fino hilo negro, lo que me permite enrollarlo sobre sí para ajustar la altura. De esta forma lo puedo colgar de algún libro de una estantería.

Y así tienes tu genial Batman colgando de tu salón. Espero te guste! Otras ideas o comentarios? Al twitter!

🐦 @RoamingWorkshop

Carcasa DFRobot para UNIHIKER

El pequeño y eficiente factor de forma de la UNIHIKER hace que sea muy fácil diseñar una carcasa para ella.

Para my asistente inteligente buscaba un estilo tipo androide, y el logo de DFRobot es perfecto para la UNIHIKER, haciendo un guiño a sus desarrolladores.

Repositorio Github

He publicado un repositorio donde abriré las fuentes (open-source) de todos los archivos de los modelos, pudiendo cualquiera contribuir con los suyos, así que anímate a crear una solicitud de cambios (pull request) y comparte tus diseños!

https://github.com/TheRoam/DFRobot-UNIHIKER-case/

También se incluye una página github donde se pueden previsualizar los modelos:

https://theroam.github.io/DFRobot-UNIHIKER-case/

Unihiker_DFRcase_v1

Mi primer lanzamiento, usado para testear e incluir las funcionalidades básicas para mi asistente.

Archivos

https://github.com/TheRoam/DFRobot-UNIHIKER-case/tree/main/blender

Características

  • Aperturas superiores para mostrar texto en la pantalla táctil.
  • Apertura lateral para conexión de USB-C.
  • Apertura trasera para cableado de sensores externos.
  • Extrusiones traseras para colocación de altavoces de 40mm.
  • Pie de soporte para posicionamiento vertical.

Partes de la carcasa

  1. Pieza inferior: actúa como envoltorio.
  2. Pieza de soporte interior: sostiene la placa UNIHIKER a la pieza inferior usando los tornillos de la placa.
  3. Pieza superior: actúa como tapa encajándose en la pieza inferior.
  4. Pie de soporte: permite posicionamiento vertical.
  5. Antenas: le dan el toque final al logo de DFRobot.

Ensamblaje

  1. Coloca los tornillos en el soporte interior y atorníllalo a la placa UNIHIKER.
  1. Coloca la UNIHIKER dentro de la pieza inferior. Si vas a usar sensores exteriores, saca el cableado por la apertura trasera.
  1. Sujeta la placa a la carcasa con un par de tornillos de 2.5mm desde la parte trasera.
  1. Coloca la pieza superior y encájala con la inferior. Hará click con dos pestañas laterales.
  1. Coloca el pie de soporte y las antenas en su sitio. Puedes pegarlos con pegamento para asegurarte de que no se mueven.

Y ahí tienes tu carcasa montada con un look muy droide!

No olvides compartir tus impresiones en Twitter!

🐦 @RoamingWorkshop

Three.js: Visor de modelos 3D para tu web

Estaba preparando un artículo donde quería insertar un modelo 3D para ilustrarlo mejor, y pensaba incluso en hacer un visor yo mismo. Pero no tuve que surfear mucho para encontrarme con Three.js.

https://threejs.org/

¡Si es que está ya todo inventado!

Enlazar la librería CDN

Para este ejemplo, haremos un visor "portable" enlazando las librerías al CDN oficial, en lugar de tener que descargarnos los ficheros a nuestro servidor.

De esta forma, el archivo de ejemplo te servirá en cualquier lugar con conexión a internet. Vamos a crear un fichero .html básico como el que nos sugieren en la documentación:

https://threejs.org/docs/index.html#manual/en/introduction/Creating-a-scene

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>My first three.js app</title>
		<style>
			body { margin: 0; }
		</style>
	</head>
	<body>
        <script async src="https://unpkg.com/[email protected]/dist/es-module-shims.js"></script>

        <script type="importmap">
          {
            "imports": {
              "three": "https://unpkg.com/[email protected]/build/three.module.js"
            }
          }
        </script>

        <script>
        //App code goes here
        </script>
	</body>
</html>

Crear una escena

Vamos a seguir con el ejemplo y rellenamos el segundo bloque <script> definiendo una escena con un cubo animado en rotación:

<script type="module">
        import * as THREE from 'three';
	const scene = new THREE.Scene();
	const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );

	const renderer = new THREE.WebGLRenderer();
	renderer.setSize( window.innerWidth, window.innerHeight );
	document.body.appendChild( renderer.domElement );

	const geometry = new THREE.BoxGeometry( 1, 1, 1 );
	const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
	const cube = new THREE.Mesh( geometry, material );
	scene.add( cube );

	camera.position.z = 5;

	function animate() {
		requestAnimationFrame( animate );

		cube.rotation.x += 0.01;
		cube.rotation.y += 0.01;

		renderer.render( scene, camera );
	};

	animate();
</script>

Todo eso, junto, queda así:

Añade controles de arrastre y un fondo

Ahora tenemos una base para trabajar. Puede añadir más funcionalidad insertando el módulo OrbitControls que maneja la rotación del modelo y de la cámara.

//Importa nuevos módulos al principio del script
import { OrbitControls } from 'https://unpkg.com/[email protected]/examples/jsm/controls/OrbitControls.js';

//luego, añade los controles del cursor después de declarar la cámara y el renderizador
const controls = new OrbitControls( camera, renderer.domElement );

También puedes modificar el fondo fácilmente, pero necesitas hospedar la imagen junto a la aplicación en un servidor, o ejecutarlo localmente, debido al CORS. Yo usaré la imagen de la cabecera del blog, que saqué de Stellarium.

Primero, define una textura. Luego, añádela a la escena:

//añade esto antes de renderizar, mientras defines la escena
//define la textura
const texture = new THREE.TextureLoader().load( "https://theroamingworkshop.cloud/demos/Unity1-north.png" );

//añade la textura a la escena
scene.background=texture;

Código completo:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>My first three.js app</title>
		<style>
			body { margin: 0; }
		</style>
	</head>
	<body>
        <script async src="https://unpkg.com/[email protected]/dist/es-module-shims.js"></script>

        <script type="importmap">
          {
            "imports": {
              "three": "https://unpkg.com/[email protected]/build/three.module.js"
            }
          }
        </script>
<body style="margin: 0; width:100%;height:300px;">
        <script async src="https://unpkg.com/[email protected]/dist/es-module-shims.js"></script>

        <script type="importmap">
          {
            "imports": {
              "three": "https://unpkg.com/[email protected]/build/three.module.js"
            }
          }
        </script>

    <script type="module">

    import * as THREE from 'three';
	import { OrbitControls } from 'https://unpkg.com/[email protected]/examples/jsm/controls/OrbitControls.js';

	const scene = new THREE.Scene();
    
	const texture = new THREE.TextureLoader().load( "https://theroamingworkshop.cloud/demos/Unity1-north.png" );
	scene.background=texture;

    const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );

	const renderer = new THREE.WebGLRenderer();
	renderer.setSize( window.innerWidth, window.innerHeight );
	document.body.appendChild( renderer.domElement );
    
    const controls = new OrbitControls( camera, renderer.domElement );

	const geometry = new THREE.BoxGeometry( 1, 1, 1 );
	const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
	const cube = new THREE.Mesh( geometry, material );
	scene.add( cube );

	camera.position.z = 5;

	function animate() {
		requestAnimationFrame( animate );

		cube.rotation.x += 0.01;
		cube.rotation.y += 0.01;

		renderer.render( scene, camera );
	};

	animate();
</script>
</body>
</html>

Insertar un modelo 3D

Ahora vamos a sustituir este cubo por un modelo 3D propio, que en el caso de Three.js, debe tener un formato glTF (.GLB o .GLTF), que es el formato más soportado y que renderiza más rápidamente (aunque también hay soporte para .fbx, .stl, .obj y demás).

Yo exportaré a .glb esta carcasa básica de Raspberry Pi 4B que hice hace un tiempo usando Blender:

Ahora, para insertar el modelo sustituimos el bloque <script> anterior basándonos en el ejemplo "webgl_loader_gltf" que se ve al inicio del post:

<script type="module">
import * as THREE from 'three';
import { GLTFLoader } from 'https://unpkg.com/[email protected]/examples/jsm/loaders/GLTFLoader.js';
import { OrbitControls } from 'https://unpkg.com/[email protected]/examples/jsm/controls/OrbitControls.js';

let camera, scene, renderer;

init();
render();

function init() {

	const container = document.createElement( 'div' );
	document.body.appendChild( container );

	camera = new THREE.PerspectiveCamera( 30, window.innerWidth / window.innerHeight, 0.1, 20 );
    camera.position.set( 0.2, 0.2, 0.2 );

	scene = new THREE.Scene();        
    scene.add( new THREE.AmbientLight( 0xffffff, 0.75 ) );

	const dirLight = new THREE.DirectionalLight( 0xffffff, 1 );
	dirLight.position.set( 5, 10, 7.5 );
	dirLight.castShadow = true;
	dirLight.shadow.camera.right = 2;
	dirLight.shadow.camera.left = - 2;
	dirLight.shadow.camera.top	= 2;
	dirLight.shadow.camera.bottom = - 2;
	dirLight.shadow.mapSize.width = 1024;
	dirLight.shadow.mapSize.height = 1024;
	scene.add( dirLight );

    //model
     const loader = new GLTFLoader();
	 loader.load( 'https://theroamingworkshop.cloud/threeJS/models/rPi4case/rPi4_case_v1.glb', function ( gltf ) {
		scene.add( gltf.scene );
		render();
	 } );

	renderer = new THREE.WebGLRenderer( { antialias: true } );
            
	renderer.setPixelRatio( window.devicePixelRatio );
	renderer.setSize( window.innerWidth, window.innerHeight );
	renderer.toneMapping = THREE.ACESFilmicToneMapping;
	renderer.toneMappingExposure = 1;
	renderer.outputEncoding = THREE.sRGBEncoding;
	container.appendChild( renderer.domElement );

	const controls = new OrbitControls( camera, renderer.domElement );
	controls.addEventListener( 'change', render );
    controls.minDistance = 0.001;
	controls.maxDistance = 1;
	controls.target.set( 0.03, 0.01, -0.01 );
	controls.update();
	window.addEventListener( 'resize', onWindowResize );
}
function onWindowResize() {
	camera.aspect = window.innerWidth / window.innerHeight;
	camera.updateProjectionMatrix();
	renderer.setSize( window.innerWidth, window.innerHeight );
	render();
}
function render() {
	renderer.render( scene, camera );
}
</script>

Básicamente se hace lo siguiente:

  • Importar módulos a usar:
    • GLTFLoader cargará nuestro modelo en formato .glb
    • OrbitControls nos permite controlar la vista de la cámara
  • Definir la escena:
    • definir una cámara
    • definir la luz (en este caso hay luz ambiente y direccional, prueba a comentar alguna de ellas y verás la diferencia)
  • Cargar el modelo en la escena
  • Definir los parámetros de renderizado y renderizar.

Y todo ello queda así (clicka y arrastra!):

Espero que te sea útil! Dudas o comentarios al 🐦 Twitter!

🐦 @RoamingWorkshop