I'm new to three.js, and I'm trying to load in my tree model, but all I see if a blank screen.
I've validated the GLB file using gltf-viewer.donmccurdy.com (though the textures didn't seem to load (I'd converted from GLTF to GLB), and I don't get any JS errors in the developer tools, so I'm at a bit of a block (at least mentally).
I've loaded the camera, I've created an Ambient light to light the object (I've reduced the code as it did have directional and point lighting as well).
I'm making the assumption that all objects are loaded at 0,0,0 in terms of coordinates. Does anyone have any experience with GLB files not rendering or where I've gone wrong.
import {
Camera,
Color,
Scene,
PerspectiveCamera,
WebGLRenderer,
AmbientLight,
} from "https://cdn.skypack.dev/three#0.132.2";
import { GLTFLoader } from 'https://cdn.skypack.dev/three#0.132.2/examples/jsm/loaders/GLTFLoader.js';
const container = document.querySelector('#scene-container');
const scene = new Scene();
const renderer = new WebGLRenderer();
const hlight = new AmbientLight (0x404040,100);
const fov = 80;
const aspect = container.clientWidth / container.clientHeight;
const near = 0.1;
const far = 100;
const camera = new PerspectiveCamera(fov, aspect, near, far);
const loader = new GLTFLoader();
scene.background = new Color('white');
camera.position.set(0, 50, 100);
scene.add(hlight);
renderer.setSize(container.clientWidth, container.clientHeight);
renderer.setPixelRatio(window.devicePixelRatio);
container.append(renderer.domElement);
loader.load('tree.glb', function(gltf){
const tree = gltf.scene.children[0];
tree.scale.set(1.5,1.5,1.5);
scene.add(gltf.scene);
});
renderer.render(scene, camera);
Related
I'm newbie to both 3JS and Blender , when I export my model to .glb , then import it to my 3JS project . But somehow they are not the same.
In Blender Rendered Mode it look so smooth but in 3JS , all the color , the mesh , ... so terrible, what did i miss to adjust in 3JS project , please help me :(
(all of my Blender setting are default)
import * as THREE from 'three';
import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls.js';
import {GLTFLoader} from 'three/examples/jsm/loaders/GLTFLoader.js'
//import img
import galaxy from '../img/galaxy.jpg';
//setting value place
const monkeyURL = new URL('../asssets/racoon_2_1.glb',import.meta.url);
const renderer = new THREE.WebGLRenderer();
renderer.gammaOutput = true;
renderer.setSize(window.innerWidth,window.innerHeight); //note this place to change the size of scene to fit the html css
document.body.appendChild(renderer.domElement);
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth/window.innerHeight,
0.1,
1000
);
//spot light
const spotLight= new THREE.SpotLight(0xFFFFFF);
scene.add(spotLight);
spotLight.position.set(00,10,10);
spotLight.castShadow=true;
const spotLight1= new THREE.SpotLight(0xFFFFFF);
scene.add(spotLight1);
spotLight1.position.set(00,10,-10);
spotLight.castShadow=true;
spotLight.angle=0.5;
const spotLightHelper = new THREE.SpotLightHelper(spotLight);
scene.add(spotLightHelper);
//change color background or image
//renderer.setClearColor(0xFFEA00);
//const textureLoader = new THREE.TextureLoader();
//scene.background = textureLoader.load(galaxy);
//model Blender
const assetLoader = new GLTFLoader();
assetLoader.load(monkeyURL.href,function(gltf){
const model = gltf.scene;
scene.add(model);
model.position.set(0,0,0);
}, undefined, function(error){
console.error(error);
});
//orbit controls
const orbit = new OrbitControls(camera, renderer.domElement);
//axes
const axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper);
//camera
camera.position.set(0,2,5);
//functions :D
orbit.update();
function animate()
{
renderer.render(scene,camera);
}
renderer.setAnimationLoop(animate);
Get some help to fix my error
I'm using CubeTextureLoader for a 3d background of 2 images and it aint working. Even though the path to images is fine and I get the images working fine in TextureLoader.
import * as THREE from "three"
import {OrbitControls} from "three/examples/jsm/controls/OrbitControls.js"
import * as dat from "dat.gui"
import nebula from './images/nebula.jpg'
import stars from './images/stars.jpg'
const renderer = new THREE.WebGLRenderer({ alpha: true });
renderer.shadowMap.enabled=true
renderer.setClearColor(0x590d18, 1);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
const orbit=new OrbitControls(camera,renderer.domElement)
const axesHelper = new THREE.AxesHelper(2);
scene.add(axesHelper);
camera.position.set(-10, 30, 30);
orbit.update()
const planeGeometry=new THREE.PlaneGeometry(30,30)
const planeMaterial=new THREE.MeshStandardMaterial({
color:0xffffff,
side:THREE.DoubleSide
})
const plane=new THREE.Mesh(planeGeometry,planeMaterial)
scene.add(plane)
plane.rotation.x=-0.5*Math.PI
plane.receiveShadow=true
const gridHelper=new THREE.GridHelper(30)
scene.add(gridHelper)
const sphereGeometry = new THREE.SphereGeometry(4,50,50);
const sphereMaterial = new THREE.MeshStandardMaterial({
color: 0x0000ff,
wireframe:false,
});
const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
scene.add(sphere);
sphere.position.set(-10,4,4)
sphere.castShadow=true
const spotLight=new THREE.SpotLight(0xFFFFFF)
scene.add(spotLight)
spotLight.position.set(-100,100,0)
spotLight.castShadow=true
spotLight.angle=0.2
const sLightHelper=new THREE.SpotLightHelper(spotLight)
scene.add(sLightHelper)
scene.fog=new THREE.FogExp2(0xFFFFFF,0.02)
//loading an image
//const textureLoader=new THREE.TextureLoader()
//scene.background=textureLoader.load(stars) THIS WORKS
const cubeTextureLoader=new THREE.CubeTextureLoader() THIS DONT
scene.background=cubeTextureLoader.load([
stars,
stars,
nebula,
stars,
stars,
stars
])
const gui=new dat.GUI()
const options={
sphereColor:'#ffea00',
wireframe:false,
speed:0.01,
angle:0.2,
penumbra:0,
intensity:1
}
gui.addColor(options,'sphereColor').onChange(function(e){
sphere.material.color.set(e)
})
gui.add(options,'wireframe').onChange(function(e){
sphere.material.wireframe=e
})
gui.add(options,"speed",0,0.1)
gui.add(options,"angle",0,1)
gui.add(options,"penumbra",0,1)
gui.add(options,"intensity",0,1)
let step=0
function animate(time) {
box.rotation.x = time/1000;
box.rotation.y = time/1000;
step+=options.speed
sphere.position.y=10*Math.abs(Math.sin(step))
spotLight.angle=options.angle;
spotLight.penumbra=options.penumbra;
spotLight.intensity=options.intensity;
sLightHelper.update()
renderer.render(scene, camera);
}
renderer.setAnimationLoop(animate)
I was expecting a 3d background , but instead I get the original black color.
I'm using CubeTextureLoader for a 3d background of 2 images and it aint working. Even though the path to images is fine and I get the images working fine in TextureLoader.
I had the same problem a while back and it turns out all the faces of the CubeTextureLoader must be squares.
So, cropping the images to have a 1:1 dimension might work.
I'm struggling to get an animation to play together with my GLTF 3D model. Most similar issues that I've seen on Stack Overflow are relating to the mixer not being updated. Which is not the problem in my case.
This is my fiddle: https://jsfiddle.net/rixi/djqz1nb5/11/
import * as THREE from "https://threejsfundamentals.org/threejs/resources/threejs/r122/build/three.module.js";
import { GLTFLoader } from "https://threejsfundamentals.org/threejs/resources/threejs/r132/examples/jsm/loaders/GLTFLoader.js";
import { OrbitControls } from "https://threejsfundamentals.org/threejs/resources/threejs/r132/examples/jsm/controls/OrbitControls.js";
let clock, controls, scene, camera, renderer, mixer, container, model;
initScene();
animate();
function initScene() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
clock = new THREE.Clock();
renderer = new THREE.WebGLRenderer();
controls = new OrbitControls(camera, renderer.domElement);
controls.update();
container = document.getElementById("container");
container.appendChild(renderer.domElement);
renderer.setSize(window.innerWidth, window.innerHeight);
}
scene.background = new THREE.Color("#f8edeb");
// LIGHT
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(2, 2, 5);
//HELPERS
const axesHelper = new THREE.AxesHelper(5);
let gridHelper = new THREE.GridHelper(30, 30);
scene.add(light, axesHelper, gridHelper);
//GLTF START
const GLTFloader = new GLTFLoader();
GLTFloader.load("https://richardlundquist.github.io/library/alice_TEST2.glb", function (gltf) {
model = gltf;
mixer = new THREE.AnimationMixer(gltf.scene);
mixer.clipAction(gltf.animations[0]).play();
scene.add(model.scene);
});
camera.position.set(0, 20, 50);
function animate() {
requestAnimationFrame(animate);
let delta = clock.getDelta();
if (mixer) {
mixer.update(clock.getDelta());
}
renderer.render(scene, camera);
}
There is no error in the console. The animation is listed in the array and plays as it should in Don McCurdy's GLTF viewer (https://gltf-viewer.donmccurdy.com/)
But for some reason it will not play in my three js setup. Any clues? I would be extremely grateful for any help or hints on how to solve the issue.
I found two critical errors here.
At the top of your code, you pull in Three r122 with GLTFLoader r132. These need to be the same revision. Try setting them all to r132.
You call getDelta() twice here:
let delta = clock.getDelta();
if (mixer) {
mixer.update(clock.getDelta());
}
The second call to getDelta() comes immediately after the first, so always returns zero delta time. Thus, the animation never moves forward.
I am experimenting with GLTF and Three.js, and I am having a devil of a time trying to get animations to work. My end goal is to be able to create keyframe animated meshes in Blender, export them to GLTF, and use them in Aframe-based WebVR scenes. At the moment, however, I'm just trying to get them to load and animate in a simple Three.js test harness page.
I'm trying to do a very basic test to get this working. I took Blender's default cube scene, removed the camera and the light, and created a keyframe animation to spin the cube 360 degrees around the Z axis. I then exported that cube to GLTF. First, I tried the GLTF export add on, and then I tried exporting it to Collada and using Cesium's tool to convert it to GLTF. Both versions of the GLTF file load and render the cube properly, but the cube does not animate.
I was able to use this same blend file and export to JSON using Three's own JSON export add on for Blender, and everything works fine there. So, I feel like I must be doing something stupid in my Javascript or there is something about GLTF I am missing.
Can anyone tell me what I'm doing wrong here? I'm getting to hair-yanking time here.
Here's the Javascript I'm trying to use for the GLTF version (specifically the binary version from Cesium's tool):
var scene = null;
var camera = null;
var renderer = null;
var mixer = null;
var clock = new THREE.Clock();
function init3D() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var ambientLight = new THREE.AmbientLight(0x080818);
scene.add(ambientLight);
var pointLight = new THREE.PointLight(0xffffff, 1, 100);
pointLight.position.set(-5, 1, 5);
scene.add(pointLight);
camera.position.z = 5;
camera.position.y = 1.5;
}
function loadScene() {
// Instantiate a loader
var loader = new THREE.GLTFLoader();
// Load a glTF resource
loader.load('gltf/SpinCube.glb',
function (gltf) {
var model = gltf.scene;
scene.add(model);
mixer = new THREE.AnimationMixer(model);
mixer.clipAction(gltf.animations[0]).play();
render();
});
}
function render() {
requestAnimationFrame(render);
var delta = clock.getDelta();
if (mixer != null) {
mixer.update(delta);
};
renderer.render(scene, camera);
}
init3D();
loadScene();
The problem appeared to have been a bug in the version of Three.js's GLTF2Loader that I was using at the time. I pulled a copy of Three.js from the dev branch, and my animations showed correctly.
I have a fairly complicated architecture where I am doing most of my stuff in Three.JS but I also have a special renderer that renders directly to a raw WebGL texture. Is it possible to use this WebGL texture in a three.js "Texture"? It looks like the Three.JS texture class is just a container for an image or video or canvas, and somewhere deep in the guts of three.js it will upload that to a real webgl texture. How can I just have Three.js render my WebGL texture onto a mesh?
#Brendan's answer no longer works.
No idea when it changed and too lazy to go look it up but as of r102
const texture = new THREE.Texture();
renderer.setTexture2D(texture, 0); // force three.js to init the texture
const texProps = renderer.properties.get(texture);
texProps.__webglTexture = glTex;
as of r103 setTexture2D no longer exists. You can use this instead
const forceTextureInitialization = function() {
const material = new THREE.MeshBasicMaterial();
const geometry = new THREE.PlaneBufferGeometry();
const scene = new THREE.Scene();
scene.add(new THREE.Mesh(geometry, material));
const camera = new THREE.Camera();
return function forceTextureInitialization(texture) {
material.map = texture;
renderer.render(scene, camera);
};
}();
const texture = new THREE.Texture();
forceTextureInitialization(texture); // force three.js to init the texture
const texProps = renderer.properties.get(texture);
texProps.__webglTexture = glTex;
'use strict';
/* global THREE */
function main() {
const canvas = document.querySelector('#c');
const renderer = new THREE.WebGLRenderer({
canvas: canvas
});
const fov = 75;
const aspect = 2; // the canvas default
const near = 0.1;
const far = 5;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.z = 2;
const scene = new THREE.Scene();
const boxWidth = 1;
const boxHeight = 1;
const boxDepth = 1;
const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
const forceTextureInitialization = function() {
const material = new THREE.MeshBasicMaterial();
const geometry = new THREE.PlaneBufferGeometry();
const scene = new THREE.Scene();
scene.add(new THREE.Mesh(geometry, material));
const camera = new THREE.Camera();
return function forceTextureInitialization(texture) {
material.map = texture;
renderer.render(scene, camera);
};
}();
const cubes = []; // just an array we can use to rotate the cubes
{
const gl = renderer.getContext();
const glTex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, glTex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 2, 2, 0,
gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([
255, 0, 0, 255,
0, 255, 0, 255,
0, 0, 255, 255,
255, 255, 0, 255,
]));
gl.generateMipmap(gl.TEXTURE_2D);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
const texture = new THREE.Texture();
forceTextureInitialization(texture);
const texProps = renderer.properties.get(texture);
texProps.__webglTexture = glTex;
const material = new THREE.MeshBasicMaterial({
map: texture,
});
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
cubes.push(cube); // add to our list of cubes to rotate
}
function render(time) {
time *= 0.001;
cubes.forEach((cube, ndx) => {
const speed = .2 + ndx * .1;
const rot = time * speed;
cube.rotation.x = rot;
cube.rotation.y = rot;
});
renderer.render(scene, camera);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
main();
<canvas id="c"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/103/three.min.js"></script>
Note: There is no such thing as "unsupported behavior" in three.js. Three.js makes no guarantee that anything you are doing today will work tomorrow. Three.js breaks whatever it wants to whenever it wants to
This is completely unsupported behaviour, but you could imitate the WebGLRenderer and set the __webglTexture property on a Texture directly. e.g.
var texure = new THREE.Texture();
var rawTexture = gl.createTexture();
texture.__webglTexture = rawTexture;
texture.__webglInit = true;
// ... use texture as a normal three.js texture ...
Again, this is completely unsupported and undefined behaviour and likely to break in future versions of three.js, but will likely work for the time being if you're after speed.
I'd instead suggest looking into WebGLRenderTarget if you can, or submitting a feature request to enable the feature correctly.