I am trying to load a flag (gif) texture to a sphere geometry in THREE.js, but the caveat is I am using React to do this.
const textureLoader = new THREE.TextureLoader();
const flag = getFlagForCountry(flags, x.id),
texture = textureLoader.load(require(`../assets/images/flags/${flag.name}.gif`));
const mat = new THREE.MeshLambertMaterial({
transparent: true,
opacity: .5,
map: texture
});
const sphere = new THREE.Mesh(new THREE.SphereGeometry(1, 10, 10), mat);
sphere.overdraw = true;
When I remove the map: texture property I am able to see the sphere in the scene, but then when I add back in the texture it is simply a black screen. I know the docs for TextureLoader say url is a string, but I am not getting any errors and in fact I am getting warnings that make it appear like something is working. Has anyone had success loading a texture onto a sphere using require() in React.
THREE.WebGLRenderer: image is not power of two (1181x788). Resized to 1024x512
<img crossorigin="anonymous" src="/static/media/Argentina.4c3ff3da.gif">
I would recommend passing the image path directly to the .load() method rather than passing it via require(). Also, I suggest using the TextureLoader callback, to ensure that your texture object is valid and fully loaded, before trying to make use of it.
You can make use of the callback in this way:
const textureLoader = new THREE.TextureLoader();
const flag = getFlagForCountry(flags, x.id)'
// Use the loaders callback
textureLoader.load(`../assets/images/flags/${flag.name}.gif`, function(texture) {
// The texture object has loaded and is now avalible to be used
const mat = new THREE.MeshLambertMaterial({
transparent: true,
opacity: .5,
map: texture
});
const sphere = new THREE.Mesh(new THREE.SphereGeometry(1, 10, 10), mat);
sphere.overdraw = true;
// Add sphere to your scene ... scene.add(sphere);
});
As a final note, consider adjusting your image filepath to an absolute path (by removing the ..) if your assets directory is located in the same directory that your webserver is running from.
Hope this helps!
import React, { Component } from "react";
import * as THREE from "three";
var earthMesh;
class ThreeScene extends Component {
componentDidMount() {
const width = this.mount.clientWidth;
const height = this.mount.clientHeight;
//ADD SCENE
this.scene = new THREE.Scene();
//ADD CAMERA
this.camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000);
this.camera.position.z = 8;
//ADD RENDERER
this.renderer = new THREE.WebGLRenderer({ antialias: true });
this.renderer.setClearColor("#263238");
this.renderer.setSize(width, height);
this.mount.appendChild(this.renderer.domElement);
//ADD CUBE
const geometry = new THREE.BoxGeometry(5, 5, 5);
const material = new THREE.MeshBasicMaterial({
color: "#0F0",
wireframe: true
});
this.cube = new THREE.Mesh(geometry, material);
this.scene.add(this.cube);
//Add SPHERE
//LOAD TEXTURE and on completion apply it on box
var loader = new THREE.TextureLoader();
loader.load(
"data:image/png;base64,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",
this.onLoad,
this.onProgress,
this.onError
);
//LIGHTS
var lights = [];
lights[0] = new THREE.PointLight(0x304ffe, 1, 0);
lights[1] = new THREE.PointLight(0xffffff, 1, 0);
lights[2] = new THREE.PointLight(0xffffff, 1, 0);
lights[0].position.set(0, 200, 0);
lights[1].position.set(100, 200, 100);
lights[2].position.set(-100, -200, -100);
this.scene.add(lights[0]);
this.scene.add(lights[1]);
this.scene.add(lights[2]);
}
componentWillUnmount() {
this.stop();
this.mount.removeChild(this.renderer.domElement);
}
start = () => {
if (!this.frameId) {
this.frameId = requestAnimationFrame(this.animate);
}
};
stop = () => {
cancelAnimationFrame(this.frameId);
};
animate = () => {
this.earthMesh.rotation.x += 0.01;
this.cube.rotation.y += 0.01;
this.renderScene();
this.frameId = window.requestAnimationFrame(this.animate);
};
renderScene = () => {
this.renderer.render(this.scene, this.camera);
};
onLoad = texture => {
var objGeometry = new THREE.SphereBufferGeometry(3, 35, 35);
var objMaterial = new THREE.MeshPhongMaterial({
map: texture,
shading: THREE.FlatShading
});
this.earthMesh = new THREE.Mesh(objGeometry, objMaterial);
this.scene.add(this.earthMesh);
this.renderScene();
//start animation
this.start();
};
onProgress = xhr => {
console.log((xhr.loaded / xhr.total) * 100 + "% loaded");
};
// Function called when download errors
onError = error => {
console.log("An error happened" + error);
};
render() {
return (
<div
style={{ width: "400px", height: "400px" }}
ref={mount => {
this.mount = mount;
}}
/>
);
}
}
export default ThreeScene;
https://codesandbox.io/embed/kw7l49nw1r
Related
I want to simulate water flow through the pipe using Three.js in my React application. As you can see in the below picture, I want to achieve three functionalities,
Draw a pipe
Simulate water based on % (0-100) - Now pipe filled with 70% of water.(user-defined)
Animate water flow using arrows moving from left to right - (left to right/ right to left) - user-defined
Something I tried was not working
A hollow cylinder (pipe), based on ExtrudeGeometry:
body{
overflow: hidden;
margin: 0;
}
<script type="module">
import * as THREE from "https://cdn.skypack.dev/three#0.133.1";
import {
OrbitControls
} from "https://cdn.skypack.dev/three#0.133.1/examples/jsm/controls/OrbitControls.js";
let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 1000);
camera.position.set(0, 0, 10);
camera.lookAt(scene.position);
let renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(innerWidth, innerHeight);
renderer.setClearColor(0x404040);
document.body.appendChild(renderer.domElement);
let controls = new OrbitControls(camera, renderer.domElement);
let light = new THREE.DirectionalLight(0xffffff, 1);
light.position.setScalar(1);
scene.add(light, new THREE.AmbientLight(0xffffff, 0.5));
let r = 1, R = 1.25;
// pipe
let pipeShape = new THREE.Shape();
pipeShape.absarc(0, 0, R, 0, Math.PI * 2);
pipeShape.holes.push(new THREE.Path().absarc(0, 0, r, 0, Math.PI * 2, true));
let pipeGeometry = new THREE.ExtrudeGeometry(pipeShape, {
curveSegments: 100,
depth: 10,
bevelEnabled: false
});
pipeGeometry.center();
let pipeMaterial = new THREE.MeshLambertMaterial({color: "silver"});
let pipe = new THREE.Mesh(pipeGeometry, pipeMaterial);
scene.add(pipe);
window.addEventListener("resize", onResize);
renderer.setAnimationLoop(_ => {
renderer.render(scene, camera);
})
function onResize(event) {
camera.aspect = innerWidth / innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(innerWidth, innerHeight);
}
</script>
It looks like your cylinder Geometry is oversized compared to your scene.
Watch the following example :
https://codepen.io/freddy-turtle/pen/OJjVmvG?editors=1010
the cylinder appear in the whole screen with CylinderGeometry = 1,1,3 as first arguments.
I am trying to create a tee-piece which is a fitting in the plumbing domain. It consist of 2 tubes that are merged together and has 3 openings as shown in this picture.
I have written some code in threejs where I am trying to create a tube mesh1 and another tube mesh2 and then try to union them into mesh3 with the library #enable3d/three-graphics/jsm/csg - thanks to #Marquizzo. After using the function CSG.union and adding the mesh to the scene I can see that I get one tee-piece but it has also created a hole in geometry 1, which was not expected. You can see a picture of the correct holes(green) and the wrongly created hole (red) here:
it should instead look like this and be as one geometry.
Can anyone tell me how CSG works and why I am getting an extra hole on the backside of the first geometry?
import React, { Component } from 'react';
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { CSG } from '#enable3d/three-graphics/jsm/csg';
export default class TubeViewer extends Component {
componentDidMount() {
//Add Scene
this.scene = new THREE.Scene();
//Add Renderer
this.renderer = new THREE.WebGLRenderer({ antialias: true });
this.renderer.setClearColor('#808080');
this.renderer.shadowMap.enabled = true;
this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
this.renderer.setPixelRatio(window.devicePixelRatio);
this.renderer.setSize(window.innerWidth, window.innerHeight);
this.mount.appendChild(this.renderer.domElement);
//Add Camera
const fov = 60;
const aspect = window.innerWidth / window.innerHeight;
const near = 1.0;
const far = 1000.0;
this.camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
this.camera.position.set(1, aspect, 1, 1000);
//Tee-piece
const curve1 = new THREE.LineCurve(new THREE.Vector3(2, 0, 0), new THREE.Vector3(2, 0, 0.1));
const curve11 = new THREE.LineCurve(new THREE.Vector3(2.0, 0, 0.05), new THREE.Vector3(2.05, 0, 0.05));
const geometry1 = new THREE.TubeGeometry(curve1, 20, 0.025, 8, false);
const geometry2 = new THREE.TubeGeometry(curve2, 20, 0.025, 8, false);
const material = new THREE.MeshBasicMaterial({ color: '#C0C0C0' });
const mesh1 = new THREE.Mesh(geometry1, material);
const mesh2 = new THREE.Mesh(geometry2, material);
const mesh3 = CSG.union(mesh1, mesh2);
this.scene.add(mesh3);
//Add raycaster to for interactivity
this.raycaster = new THREE.Raycaster();
this.mouse = new THREE.Vector2();
this.renderer.domElement.addEventListener('click', onClick.bind(this), false);
function onClick(event) {
event.preventDefault();
this.mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
this.mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
this.raycaster.setFromCamera(this.mouse, this.camera);
var intersects = this.raycaster.intersectObjects(this.scene.children, true);
if (intersects.length > 0) {
console.log('Intersection:', intersects[0]);
//console.log(intersects[0].object.uuid);
// console.log(`GUID: ${intersects[0]}`);
let object = intersects[0].object;
object.material.color.set(Math.random() * 0xffffff);
}
}
//Settings
//Add Camera Controls
const controls = new OrbitControls(this.camera, this.renderer.domElement);
controls.addEventListener('change', this.render); // use if there is no animation loop
controls.minDistance = 2;
controls.maxDistance = 10;
controls.target.set(0, 0, -0.2);
controls.update();
///Add AMBIENT LIGHT
let light = new THREE.DirectionalLight(0xffffff, 1.0);
light.position.set(20, 100, 10);
light.target.position.set(0, 0, 0);
light.castShadow = true;
light.shadow.bias = -0.001;
light.shadow.mapSize.width = 2048;
light.shadow.mapSize.height = 2048;
light.shadow.camera.near = 0.1;
light.shadow.camera.far = 500.0;
light.shadow.camera.near = 0.5;
light.shadow.camera.far = 500.0;
light.shadow.camera.left = 100;
light.shadow.camera.right = -100;
light.shadow.camera.top = 100;
light.shadow.camera.bottom = -100;
this.scene.add(light);
light = new THREE.AmbientLight(0xffffff, 0.7);
this.scene.add(light);
//Start animation
this.start();
}
//Unmount when animation has stopped
componentWillUnmount() {
this.stop();
this.mount.removeChild(this.renderer.domElement);
}
//Function to start animation
start = () => {
//Rotate Models
if (!this.frameId) {
this.frameId = requestAnimationFrame(this.animate);
}
};
//Function to stop animation
stop = () => {
cancelAnimationFrame(this.frameId);
};
//Animate models here
animate = () => {
//ReDraw scene with camera and scene object
if (this.cubeMesh) this.cubeMesh.rotation.y += 0.01;
this.renderScene();
this.frameId = window.requestAnimationFrame(this.animate);
};
//Render the scene
renderScene = () => {
if (this.renderer) this.renderer.render(this.scene, this.camera);
};
render() {
return (
<div
style={{ width: '800px', height: '800px' }}
ref={(mount) => {
this.mount = mount;
}}
/>
);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
enter code here?
For CSG you'll need solid bodies. These tubes are open.
I created an example using cylinders (tubes are involved to cap) so you can test it.
These cylinders are open ended, so they fail in the same way as your tubes.
https://codepen.io/flatworldstudio/pen/bGBjmrP
const geometry1 = new THREE.CylinderGeometry(0.1, 0.1, 0.5, 20, 1, true);
These are closed, and CSG works as expected.
https://codepen.io/flatworldstudio/pen/VwmBRoL
const geometry1 = new THREE.CylinderGeometry(0.1, 0.1, 0.5, 20, 1, false);
(I'm using a different version of CSG, but they all seem to be built on the same code)
Single GLTF element i can drag and drop. but group of element i can't drag. I am using following code
var loader = new THREE.GLTFLoader();
loader.load( 'W3030/W3030.gltf', ( gltf ) => {
gltf.scene.traverse( function( child ) {
if(child.type === "Group")
{
newObject = true;
GLTFobjects.push(child);
}
if ( child.isMesh ) {
child.receiveShadow = true;
child.castShadow = true;
child.material.transparent = true;
child.material.opacity = 1;
}
});
scene.add(GLTFobjects);
gltf.scene.scale.set(1, 1, 1);
});
I'm afraid instances of Group are not supported by DragControls since there is no Group.raycast() method.
You can implement a workaround by replacing groups with invisible meshes. However, instead of setting Object3D.visible to false, you do this for Material.visible. Otherwise the raycasting logic will not perform the intersection test. It's then necessary to use a geometry that is large enough to enclose the respective children.
three.js R110
Hi Thanks for your support. Now i drag.
Use following code to drag multi mesh GLTF. It is Work for me.
var dragobjects =[];
//add following code in init function
var gltfobject = addGLTFObjectIntoScene();
scene.add(gltfobject);
dragControls = new THREE.DragControls(dragobjects, camera, renderer.domElement);
dragControls.addEventListener('dragstart', onDragStart, false);
dragControls.addEventListener('drag', onDrag , false);
dragControls.addEventListener('dragend', onDragEnd, false);
//end init function code
//add following function after or before init function
function drawBox(objectwidth,objectheight,objectdepth){
var geometry, material, box;
geometry = new THREE.BoxGeometry(objectwidth,objectheight,objectdepth);
material = new THREE.MeshBasicMaterial({color: 0xffff00, transparent: true, opacity: 0,depthTest:false});
box = new THREE.Mesh(geometry, material);
dragobjects.push(box);
box.position.set(0, 0, 0);
return box;
};
function addGLTFObjectIntoScene(){
group = new THREE.Group();
var loader = new THREE.GLTFLoader();
loader.load( 'W1230/W1230.gltf', ( gltf ) => {
mesh = gltf.scene;
mesh.scale.set( 30, 30, 30);
var gltfbox = new THREE.Box3().setFromObject( mesh );
var objectwidth = Math.floor(gltfbox.getSize().x);
var objectheight = Math.floor(gltfbox.getSize().y);
var objectdepth = Math.floor(gltfbox.getSize().z);
objectwidth = objectwidth + parseInt(2);
objectheight = objectheight + parseInt(2);
objectdepth = objectdepth + parseInt(1);
mesh.position.set(0, -objectheight/2, 0);
box = drawBox(objectwidth,objectheight,objectdepth);
group.add(box);
group.name = "quadrant";
console.log(mesh);
box.add( mesh);
});
return group;
};
I am working on a multipage pdf download using html2canvas and pdfmake.
I am able to download the pdf but page height, page width of the generated pdf is not proper and the resolution is low/blur. The code is as below. Please refer the screenshot attached herewith.
Thanks in advance.
Code I have used is:
html2canvas(document.getElementById('newId')).then(
canvas=>{
var image = canvas.toDataURL('image/png');
const PAGE_WIDTH = 500;
const PAGE_HEIGHT = 700;
const content = [];
var w=500;
var h=700;
function getPngDimensions (base64) {
const header = atob(base64.slice(22, 70)).slice(16, 24);
const uint8 = Uint8Array.from(header, c => c.charCodeAt(0));
const dataView = new DataView(uint8.buffer);
return {
width: dataView.getInt32(0),
height: dataView.getInt32(4)
};
}
const splitImage = (img, content, callback) => () => {
const canvas = document.createElement('canvas');
canvas.width = w*2;
canvas.height=h*2;
canvas.style.width=w+'px';
canvas.style.height=h+'px';
const ctx = canvas.getContext('2d');
ctx.scale(2,2);
const printHeight = img.height * PAGE_WIDTH / img.width;
for (let pages = 0; printHeight > pages * PAGE_HEIGHT; pages++) {
canvas.height = Math.min(PAGE_HEIGHT, printHeight - pages * PAGE_HEIGHT);
ctx.drawImage(img, 0, -pages * PAGE_HEIGHT, img.width, printHeight);
content.push({ image: canvas.toDataURL(), margin: [0, 5],width:PAGE_WIDTH });
}
callback();
};
function next () {
pdfMake.createPdf({ content }).open();
}
const { width, height } = getPngDimensions(image);
const printHeight = height * PAGE_WIDTH / width;
if (printHeight > PAGE_HEIGHT) {
const img = new Image();
img.onload = splitImage(img, content, next);
img.src = image;
return;
}
content.push({ image, margin: [0, 5], width: PAGE_WIDTH });
next();
}
);
Update:
I tried updating the width and height of the image formed by the canvas but increasing the width onl increases the pixel size and further truncates the right end of the dashboard.
const PAGE_WIDTH = 500;
const PAGE_HEIGHT = 700;
//some more code here as mentioned in the detailed snippet
const content = [];
var w=500;
var h=700;
Poor Pixel Display For Multi Page PDF Through Banana Dashboard
I have tried import babylonjs in react but its is not working. Does any body know how to import and use the babylonjs in reactjs application.
Thanks.
Not sure if you have found the answer on your own, however there are several ways now as babylon has matured. There is actually a Node package for using babylon.js with react here: https://www.npmjs.com/package/react-babylonjs
Also there is an install guide for React in Babylon.js in the docs:
https://doc.babylonjs.com/resources/babylonjs_and_reactjs
Hope that helps!
Babylon JS is available as npm package. You can easily build a simple React Component around a canvas and Babylon JS
I have created a minimal example with React+ Babylon:
/* Babylon JS is available as **npm** package.
You can easily build a simple `React` Component around a `canvas` and Babylon JS
I have created a minimal example with React+ Babylon:
*/
import React, { Component } from "react";
import * as BABYLON from "babylonjs";
var scene;
var boxMesh;
/**
* Example temnplate of using Babylon JS with React
*/
class BabylonScene extends Component {
constructor(props) {
super(props);
this.state = { useWireFrame: false, shouldAnimate: false };
}
componentDidMount = () => {
// start ENGINE
this.engine = new BABYLON.Engine(this.canvas, true);
//Create Scene
scene = new BABYLON.Scene(this.engine);
//--Light---
this.addLight();
//--Camera---
this.addCamera();
//--Meshes---
this.addModels();
//--Ground---
this.addGround();
// Add Events
window.addEventListener("resize", this.onWindowResize, false);
// Render Loop
this.engine.runRenderLoop(() => {
scene.render();
});
//Animation
scene.registerBeforeRender(() => {
boxMesh.rotation.y += 0.01;
boxMesh.rotation.x += 0.01;
});
};
componentWillUnmount() {
window.removeEventListener("resize", this.onWindowResize, false);
}
onWindowResize = event => {
this.engine.resize();
};
/**
* Add Lights
*/
addLight = () => {
//---------- LIGHT---------------------
// Create a basic light, aiming 0,1,0 - meaning, to the sky.
var light = new BABYLON.HemisphericLight(
"light1",
new BABYLON.Vector3(0, 10, 0),
scene
);
};
/**
* Add Camera
*/
addCamera = () => {
// ---------------ArcRotateCamera or Orbit Control----------
var camera = new BABYLON.ArcRotateCamera(
"Camera",
Math.PI / 2,
Math.PI / 4,
4,
BABYLON.Vector3.Zero(),
scene
);
camera.inertia = 0;
camera.angularSensibilityX = 250;
camera.angularSensibilityY = 250;
// This attaches the camera to the canvas
camera.attachControl(this.canvas, true);
camera.setPosition(new BABYLON.Vector3(5, 5, 5));
};
/**
* Create Stage and Skybox
*/
addGround = () => {
// Create a built-in "ground" shape.
var ground = BABYLON.MeshBuilder.CreateGround(
"ground1",
{ height: 6, width: 6, subdivisions: 2 },
scene
);
var groundMaterial = new BABYLON.StandardMaterial("grass0", scene);
groundMaterial.diffuseTexture = new BABYLON.Texture(
"./assets/ground.jpeg",
scene
);
ground.material = groundMaterial;
//Add SkyBox
var photoSphere = BABYLON.Mesh.CreateSphere("skyBox", 16.0, 50.0, scene);
var skyboxMaterial = new BABYLON.StandardMaterial("smat", scene);
skyboxMaterial.emissiveTexture = new BABYLON.Texture(
"assets/skybox.jpeg",
scene,
1,
0
);
skyboxMaterial.diffuseColor = new BABYLON.Color3(0, 0, 0);
skyboxMaterial.specularColor = new BABYLON.Color3(0, 0, 0);
skyboxMaterial.emissiveTexture.uOffset = -Math.PI / 2; // left-right
skyboxMaterial.emissiveTexture.uOffset = 0.1; // up-down
skyboxMaterial.backFaceCulling = false;
photoSphere.material = skyboxMaterial;
};
/**
* Add Models
*/
addModels = () => {
// Add BOX
boxMesh = BABYLON.MeshBuilder.CreateBox(
"box",
{ height: 1, width: 1, depth: 1 },
scene
);
boxMesh.position.y = 1;
var woodMaterial = new BABYLON.StandardMaterial("wood", scene);
woodMaterial.diffuseTexture = new BABYLON.Texture(
"./assets/portal_cube.png",
scene
);
boxMesh.material = woodMaterial;
};
render() {
return (
<canvas
style={{ width: window.innerWidth, height: window.innerHeight }}
ref={canvas => {
this.canvas = canvas;
}}
/>
);
}
}
export default BabylonScene;
Live Demo:
https://codesandbox.io/s/babylonjs-react-template-w2i1k