Hello I'm trying to import an fbx model into my scene, but there is not much info on it online I had found one way that looks to use official three.js package but for some reason the model dose not appear in my scene, even through I don't get any errors. If any one can help me please because I have no clue at why it is not loading.
The guide that I used: https://sbcode.net/threejs/loaders-fbx/
The short version of the code.
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader'
const fbxLoader = new FBXLoader()
fbxLoader.load('models/3dModdleOfTheBox.fbx', (object) => {
scene.add(object)
})
Full code
import React, { useEffect } from 'react'
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader'
export default function Threed_model() {
//three js
useEffect(() => {
//basic setup
const scene = new THREE.Scene()
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
)
camera.position.z = 5
const renderer = new THREE.WebGLRenderer({
canvas: document.querySelector('#canvas'),
})
renderer.setPixelRatio(window.devicePixelRatio)
renderer.setSize(window.innerWidth, window.innerHeight)
//controls
const controls = new OrbitControls(camera, renderer.domElement)
controls.enableZoom = false
controls.enablePan = false
controls.target.set(0, 0, 0)
//fbx loader
const material = new THREE.MeshNormalMaterial()
const fbxLoader = new FBXLoader()
fbxLoader.load('models/3dModdleOfTheBox.fbx', (object) => {
scene.add(object)
})
//light
const light = new THREE.PointLight()
light.position.set(0.8, 1.4, 1.0)
scene.add(light)
const ambientLight = new THREE.AmbientLight()
scene.add(ambientLight)
//adding stuff
const geometry = new THREE.TorusGeometry(1, 0.5, 16, 100)
const torus = new THREE.Mesh(geometry, material)
scene.add(torus)
function animate() {
requestAnimationFrame(animate)
renderer.render(scene, camera)
}
animate()
renderer.render(scene, camera)
}, [])
return <canvas id="canvas">test</canvas>
}
Turns out you have to set a scale for your model for it to display
object.scale.set(0.01, 0.01, 0.01)
My final code looked like this for who ever might need it.
fbxLoader.load('models/3dModdleOfTheBox.fbx', (object) => {
object.traverse(function (child) {
if (child.isMesh) {
console.log(child.geometry.attributes.uv)
const texture = new THREE.TextureLoader().load(
'models/pakage(12).png'
)
child.material.map = texture
child.material.needsUpdate = true
}
})
object.scale.set(0.01, 0.01, 0.01)
scene.add(object)
console.log(object)
})
Related
I found that it seems to be solved by setting the blending attribute of material, but it still cannot be solved after trying.
Incorrect occlusion
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import {GLTFLoader} from "three/examples/jsm/loaders/GLTFLoader.js"
import {
CSS3DRenderer,
CSS3DObject
} from "three/examples/jsm/renderers/CSS3DRenderer.js"
import dat from "dat.gui"
function initThree() {
const scene = new THREE.Scene();
const scene2 = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
50,
window.innerWidth / window.innerHeight,
0.1,
10000
);
camera.position.set(0, 0, 2500);
scene.add(camera);
const renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true,
});
renderer.shadowMap.enabled = true;
renderer.setSize(window.innerWidth, window.innerHeight);
document.querySelector('#webgl').appendChild(renderer.domElement);
const labelRenderer = new CSS3DRenderer()
labelRenderer.setSize(window.innerWidth, window.innerHeight);
labelRenderer.domElement.style.position = 'absolute';
labelRenderer.domElement.style.top = 0;
document.body.appendChild(labelRenderer.domElement);
scene.add(new THREE.AxesHelper(1000))
const controls = new OrbitControls(camera, labelRenderer.domElement);
controls.enableDamping = true;
const clock = new THREE.Clock()
window.addEventListener("resize", () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
labelRenderer.setSize(window.innerWidth, window.innerHeight);
});
return {
scene,
scene2,
camera,
renderer,
labelRenderer,
controls,
clock,
}
}
const gltfLoader = new GLTFLoader()
const textureLoader = new THREE.TextureLoader()
const gui = new dat.GUI()
const {
scene,
scene2,
camera,
renderer,
labelRenderer,
controls,
clock
} = initThree();
const ambientLight = new THREE.AmbientLight("#ffffff", 1)
scene.add(ambientLight)
const position = new THREE.Vector3(0, 900, 300);
const rotation = new THREE.Euler(0, 0, 0);
const container = document.createElement('div');
container.style.width = '1000px';
container.style.height = '1000px';
container.style.opacity = '1';
container.style.background = '#1d2e2f';
const iframe = document.createElement('iframe');
iframe.src = "http://csyedu.top"
iframe.style.width = "1000px"
iframe.style.height = "1000px"
iframe.style.padding = 10 + 'px';
iframe.style.boxSizing = 'border-box';
iframe.style.opacity = '1';
container.appendChild(iframe);
const object = new CSS3DObject(container);
// copy monitor position and rotation
object.position.copy(position);
object.rotation.copy(rotation);
// Add to CSS scene
scene2.add(object);
// Create GL plane
const material = new THREE.MeshLambertMaterial();
material.side = THREE.DoubleSide;
material.opacity = 0;
material.transparent = true;
// NoBlending allows the GL plane to occlude the CSS plane
material.blending = THREE.NoBlending;
// Create plane geometry
const geometry = new THREE.PlaneGeometry(1000, 1000);
// Create the GL plane mesh
const mesh = new THREE.Mesh(geometry, material);
// Copy the position, rotation and scale of the CSS plane to the GL plane
mesh.position.copy(object.position);
mesh.rotation.copy(object.rotation);
mesh.scale.copy(object.scale);
// Add to gl scene
scene.add(mesh);
gltfLoader.load("./models/computer_setup.glb", model => {
const texture = textureLoader.load("./models/baked_computer.jpg");
texture.flipY = false;
texture.encoding = THREE.sRGBEncoding;
const material = new THREE.MeshBasicMaterial({
map: texture,
});
model.scene.traverse((child) => {
if (child instanceof THREE.Mesh) {
child.scale.set(900, 900, 900);
child.material.map = texture;
child.material = material;
}
});
scene.add(model.scene)
})
function render() {
const elapsedTime = clock.getElapsedTime();
controls.update();
renderer.render(scene, camera);
labelRenderer.render(scene2, camera)
requestAnimationFrame(render);
}
render();
The effect I want is that the 3D mesh can correctly occlude the CSS3DObject.
I runned over the same problem, I'm trying your code and works good on my project, I think you have a styling problem.
I have separated the WebGL and CSS3DRenderer on the html.
<body>
<div id="css"></div>
<div id="webgl"></div>
</body>
#css,
#webgl
{
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
}
If I only put the #css on absolute this is the result
If I put both in absolute it works fine.
I wish that'll help
I'm using threejs to provide a 3D animation...
this is my main.js file content:
import './style.css'
import {
AxesHelper,
BufferGeometry,
Float32BufferAttribute,
MathUtils,
PerspectiveCamera,
Points,
PointsMaterial,
Scene,
TextureLoader,
VertexColors,
WebGLRenderer,
} from "three";
import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls.js';
const count = 100;
const distance = 2;
const textureLoader = new TextureLoader();
const circleTexture = textureLoader.load("ball.png");
const scene = new Scene();
scene.add(new AxesHelper());
const camera = new PerspectiveCamera(75,window.innerWidth/window.innerHeight,0.01,1000);
camera.position.z = 2;
camera.position.y = 0.5;
camera.position.x = 0.5;
scene.add(camera);
const pts = new Float32Array(count * 3);
const colors = new Float32Array(count * 3);
for (let i = 0; i < pts.length; i++) {
pts[i] = MathUtils.randFloatSpread(distance * 2);
colors[i] = Math.random();
}
const geometry = new BufferGeometry();
geometry.setAttribute('position', new Float32BufferAttribute(pts,3));
geometry.setAttribute('colors', new Float32BufferAttribute(colors,3));
const pointMaterial = new PointsMaterial({
size: 0.1,
map : circleTexture,
alphaTest: 0.01,
transparent: true,
vertexColors : VertexColors,
});
const points = new Points(geometry, pointMaterial);
scene.add(points);
const renderer = new WebGLRenderer({
antialias: true, //removing all ugly pixels from cube's sides
alpha : true,
});
renderer.setClearColor(0x000000, 0);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio,2));
document.body.appendChild(renderer.domElement);
const controls = new OrbitControls(camera, renderer.domElement);
function anime() {
renderer.render(scene, camera);
controls.update();
requestAnimationFrame(anime);
}
anime();
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix(); // mettre a jour la camera...
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio,2));
});
in PointsMaterial() constructor , I want to assign a value to vertexColor to make a variety of colors for my objects (3D looking points...), but I got the following error on the console :
Uncaught SyntaxError: The requested module '/node_modules/.vite/deps/three.js?v=19235266' does not provide an export named 'VertexColors' (at main.js?t=1655672405709:13:5)
it seems like threejs doesn't contain this property or what ??!!!
I have created bottle in blender. If i test it on threejs editor it is giving right results.
But when I render it on my site it is giving
This as output. I am but new to threejs
import './style.css'
import * as THREE from 'three'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
const updateAllMaterials = () =>
{
scene.traverse((child) =>
{
if(child instanceof THREE.Mesh)
{
child.material.envMap = environmentMap
child.material.transparent = true
child.material.opacity = 0.1
child.material.envMapIntensity = 5
const material = new THREE.MeshPhysicalMaterial( {
transmission: 1, // use material.transmission for glass materials
opacity: 0.2,
color:"blue",
transparent: true
} );
child.material = material
}
})
}
// Canvas
const canvas = document.querySelector('canvas.webgl')
const gltfLoader = new GLTFLoader()
gltfLoader.load('/models/wine5.glb',(bottle)=>{
bottle.scene.scale.set(0.5,0.45,0.5)
bottle.scene.rotation.set(-0.5,1,0.3)
bottle.scene.position.set(-1,-1.5,2)
updateAllMaterials()
scene.add(bottle.scene)
})
// Scene
const scene = new THREE.Scene()
const axesHelper = new THREE.AxesHelper( 5 );
scene.add( axesHelper );
const directionalLights = new THREE.PointLight('#fff',4)
directionalLights.position.set(-0.4,2,5)
scene.add(directionalLights)
/**
* Sizes
*/
const sizes = {
width: window.innerWidth,
height: window.innerHeight
}
/**
* Camera
*/
// Base camera
const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height, 0.1, 100)
scene.add(camera)
// ENV MAPS
const singleTextureLoader = new THREE.TextureLoader()
singleTextureLoader.load('/BG/tree.jpg',(img)=>{
scene.background = img
})
/**
* Renderer
*/
const renderer = new THREE.WebGLRenderer({
canvas: canvas,
antialias: true
})
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
renderer.physicallyCorrectLights = true
renderer.outputEncoding = THREE.sRGBEncoding
renderer.toneMapping = THREE.ACESFilmicToneMapping
renderer.toneMappingExposure = 1
renderer.depth = false
Your updateAllMaterials() is traversing an empty scene, thus not applying the material to anything. Just swap the calls like this:
scene.add(bottle.scene)
updateAllMaterials()
Also, inside the updateAllMaterials() function, you are changing some parameters of the child's material, and then you overwrite the material itself, losing all the changes.
It should be something like this:
const material = new THREE.MeshPhysicalMaterial({
transmission: 1,
opacity: 0.2,
color:"blue",
transparent: true,
envMap: environmentMap,
transparent: true,
opacity: 0.1,
envMapIntensity: 5
});
child.material = material
smile on shirt has black background
smile with transparent true
GOAL: I would like users to be able to add images/colors with buttons
PROBLEM: but the png image texture(smiley face) loaded with textureLoader() has black background and lines crossing the image. :frowning:
MINOR PROBLEM:
(1) Are there any ways to match the background color of the image and the obj/gltf(shirt) that I load?
Here are my codes.
const colorSelection = {
"pink": "#ff2d55",
"purple": "#5856d6",
"blue": "#007aff",
"orange": "#ff9500",
}
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
const renderer = new THREE.WebGLRenderer({ antialias: true });
const loader = new THREE.OBJLoader();
const myCanvas = document.getElementById("container");
const controls = new THREE.OrbitControls(camera, renderer.domElement);
const axisHelper = new THREE.AxisHelper(5);
const hlight = new THREE.AmbientLight (0x404040);
const directionalLight = new THREE.DirectionalLight(0xffffff,0.4);
const geometry = new THREE.SphereGeometry(50,50,50);
const texture = new THREE.TextureLoader().load("assets/smile2.png");
const newMat = new THREE.MeshPhongMaterial({ map: texture });
myCanvas.appendChild( renderer.domElement );
renderer.setSize( 800, 800 );
renderer.setClearColor ("darkgrey", 1);
camera.position.set(200,300,200);
controls.addEventListener("change", animate);
function animate() {
requestAnimationFrame( animate );
renderer.render( scene, camera );
};
// SCENES and LIGHTING
scene.add(axisHelper);
scene.add(hlight);
scene.add(directionalLight);
directionalLight.position.set(0,1155,325);
directionalLight.castShadow = true;
function changeTextureColor(color) {
loader.load("assets/standard-t-shirt/source/tshirt.obj", function(obj) {
obj.scale.set(0.4,0.4,0.4)
obj.position.set(0,-500,0)
obj.traverse((child) => {
if (child instanceof THREE.Mesh) {
child.material.emissive = new THREE.Color(colorSelection[color])
console.log(child.material)
}
})
console.log(obj.children)
obj.children[0].material = newMat
scene.add(obj)
})
}
document.querySelectorAll("button").forEach(colorBtn => colorBtn.addEventListener("click", function () {
console.log(this.id)
const userColor = this.id;
changeTextureColor(userColor);
}))
Thanks so much for reading!
You need the transparent: true setting when creating your material, like so:
const newMat = new THREE.MeshPhongMaterial({ map: texture, transparent: true });
I am using ThreeJS to "open" and view 3D files.
At this moment I can only observe a 3D figure in 3D format.
How can I replace this geometrical figure (cube) with a 3D file (obj or fbx)?
In the project I placed two 3D files (one fbx and the other obj) with the name image.
Do I need to use any specific loader to read this type of files?
Can someone help me?
Thanks !
DEMO
html
<canvas #canvas></canvas>
.ts
#ViewChild('canvas') canvasRef: ElementRef;
renderer = new THREE.WebGLRenderer;
scene = null;
camera = null;
controls = null;
mesh = null;
light = null;
private calculateAspectRatio(): number {
const height = this.canvas.clientHeight;
if (height === 0) {
return 0;
}
return this.canvas.clientWidth / this.canvas.clientHeight;
}
private get canvas(): HTMLCanvasElement {
return this.canvasRef.nativeElement;
}
constructor() {
this.scene = new THREE.Scene();
this.camera = new THREE.PerspectiveCamera(35, 800/640, 0.1, 1000)
}
ngAfterViewInit() {
this.configScene();
this.configCamera();
this.configRenderer();
this.configControls();
this.createLight();
this.createMesh();
this.animate();
}
configScene() {
this.scene.background = new THREE.Color( 0xdddddd );
}
configCamera() {
this.camera.aspect = this.calculateAspectRatio();
this.camera.updateProjectionMatrix();
this.camera.position.set( -15, 10, 15 );
this.camera.lookAt( this.scene.position );
}
configRenderer() {
this.renderer = new THREE.WebGLRenderer({
canvas: this.canvas,
antialias: true,
alpha: true
});
this.renderer.setPixelRatio(devicePixelRatio);
this.renderer.setClearColor( 0x000000, 0 );
this.renderer.setSize(this.canvas.clientWidth, this.canvas.clientHeight);
}
configControls() {
this.controls = new OrbitControls(this.camera, this.canvas);
this.controls.autoRotate = false;
this.controls.enableZoom = true;
this.controls.enablePan = true;
this.controls.update();
}
createLight() {
this.light = new THREE.PointLight( 0xffffff );
this.light.position.set( -10, 10, 10 );
this.scene.add( this.light );
}
createMesh() {
const geometry = new THREE.BoxGeometry(5, 5, 5);
const material = new THREE.MeshLambertMaterial({ color: 0xff0000 });
this.mesh = new THREE.Mesh(geometry, material);
this.scene.add(this.mesh);
}
animate() {
window.requestAnimationFrame(() => this.animate());
// this.mesh.rotation.x += 0.01;
// this.mesh.rotation.y += 0.01;
this.controls.update();
this.renderer.render(this.scene, this.camera);
}
Do I need to use any specific loader to read this type of files?
Yes. You have to use THREE.OBJLoader and THREE.FBXLoader if you want to load OBJ or FBX files. For loading OBJ files, the workflow looks like so:
Import the loader:
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader.js';
Load the asset and add it to your scene:
const loader = new OBJLoader();
loader.load('https://threejs.org/examples/models/obj/tree.obj', object => {
this.scene.add(object);
});
BTW: There is no need to use the npm package #avatsaev/three-orbitcontrols-ts. You can import OrbitControls from the three package.
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';