Collada Model Renders on Mouse Movement - three.js

I cant get my collada model to render with three.js until I interact with the browser window. In Chrome, it can be as simple as moving my mouse anywhere on the page (actual canvas is smaller than entire window), and on Safari, it requires a click and drag for the model to render. What's odd is that the rest of the scene is loading properly (I have a grid that I render to the scene and a couple of lights), but the model won't show until I do something. Any thoughts on how I can trick the scene into knowing it should show the model?
var loader = new THREE.ColladaLoader();
loader.options.convertUpAxis = true;
loader.load('../MODELS/teapot.dae', function colladaReady( collada ) {
dae = collada.scene;
skin = collada.skins[ 0 ];
dae.scale.x = dae.scale.y = dae.scale.z = 10;
dae.position.y = 75;
dae.updateMatrix();
scene.add(dae);
});
document.getElementById('myCanvas').appendChild(renderer.domElement);
render();

The loading is occurring asynchronously. You are only showing a code fragment, but it looks like you can move the render() call to the last line of the colladaReady() callback function.

Related

Drawing mode on lower canvas and how to render controls on upper canvas instead of lower

Im started to develop my project, where fabric js canvas used as a texture on my 3d object, loaded by three js library. Unfortunately I don`t have a full working snippet now, maybe you can show me solution or right way to solve my problem
The problem is the controls drawing on the lower canvas and its transfer on my 3d object, i want to render it on the upper canvas. Is it possible?
The second problem is the brush at first rendered on the upper canvas and after event 'mouse: up' its rendered on the lower canvas. How to render brush line by event 'mouse; move' on the lower canvas at the moment drawing?
p.s. sorry for my english, its really hard to say for me. Hope, you understand my mind
Here you can see my first issue:
https://1drv.ms/u/s!AqtIFlFVWz4MhNtBc3g1DQElfA6_7Q?e=y7ly37
Thank you for you response!
Woow! this is a very good code example! And it works pretty smooth too. It shows the problem a lot better.
I found a solution for the first problem (that is kind of a three.js problem) in the fabric js demo: http://fabricjs.com/controls-customization.
I'm not good with fabric so there might be a more elegant solution than this. You can hide the controls, render to three.js and then show them again. You also have to force the canvas to render, it won't work otherwise.
function animate() {
requestAnimationFrame(animate);
//find the selected object on the fabric canvas
let selected = canvas.getActiveObject();
//hide controles and render on the fabric canvas;
if (selected){
selected.hasControls = false;
selected.hasBorders = false;
canvas.renderAll();
}
//update texture and render
texture.needsUpdate = true;
renderer.render(scene, camera);
//show controls and render on the fabric canvas
if (selected){
selected.hasControls = true;
selected.hasBorders = true;
canvas.renderAll();
}
}
The second problem is a bit harder to understand. I'm not sure what the 'lower canvas' is and if that is a part of fabric that i don't understand. This is the closest i can get. I almost made it work on the three.js renderer. If i understood the idea correctly...
You need to have a variable to know if you are pressing the mouse or not. Only if you are pressing the mouse AND moving the mouse, it draws a circle.
To do the same with fabric 'mouse:move' you will at least have to disable that selectionbox on the fabric canvas. But i do not know how that works in fabric.
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
var mouseDown = false;///////////////////////////// global boolean
var onClickPosition = new THREE.Vector2();
container.addEventListener("mousedown", function(){
mouseDown = true;
canvas.selection = false;
onMouseEvt(); //draw circle
}, false);
container.addEventListener("mouseup", function(){
mouseDown = false
canvas.selection = true;
}, false);
container.addEventListener("mousemove", function(e){
if (mouseDown){
onMouseEvt(); //draw circle
}
}, false);
///This code does not work, it goes into selection mode..
canvas.on('mouse:down', function(){
mouseDown = true;
addCircle();
}, false);
canvas.on('mouse:up', function(){
mouseDown = false;
}, false);
canvas.on('mouse:move', function(){
if ( mouseDown ){
addCircle();
}
}, false);
This is a hard question and it's not really a three.js thing, it has more to do with fabric.js and drawing to a canvas. The three.js part of texturing the object seems to work fine.
If I understand correctly you have an overlaying canvas on which you want to render the controls, but they are also rendered to the actual texture canvas? If in case you are actually rendering the controls on the texture; don't do that :p
It should be possible to make it work the way you want to. It would be helpful to post a small code example on https://jsfiddle.net/ or something.

Attempts to load a texture show no error but the texture does not display

I have a model, a background sky and a ground surface. Texturing the surface results in no surface.
I've tried the basic approach and come to the conclusion that it is probably that the scene is being rendered before the texture has finished loading. Having searched and found various possible solutions, I have tried several of them, without really understanding how they are supposed to work. None of them has worked. One problem is that it is an old problem and most of the suggestions involve outdated versions of the three.js library.
// Ground
// create a textured Ground based on an answer in Stackoverflow.
var loader = new THREE.TextureLoader();
loader.load('Textures/Ground128.jpg',
function (texture) {
var groundGeometry = new THREE.PlaneBufferGeometry(2000, 2000, 100, 100);
const groundMaterial = new THREE.MeshLambertMaterial({map: texture});
var ground = new THREE.Mesh(groundGeometry, groundMaterial);
ground.receiveShadow = true; //Illumination addition
ground.rotation.x = -0.5 * Math.PI; // rotate into the horizontal.
scene.add(ground);
}
);
// This variation does not work either
http://lhodges.users37.interdns.co.uk/me/downloads/Aphaia/Temple.htm
http://lhodges.users37.interdns.co.uk/me/downloads/Aphaia/Temple7jsV0.15b.htm
The first of the above is the complete page in which the ground is a plain billiard table green. The second is the page containing the above code.
There appear to be no error (Last time I tried.)
By the time your texture loads and you add the ground, your scene has already rendered (and there is no other render call).
You need to call renderer.render(scene, camera); after adding the ground to the scene.
// Ground
// create a textured Ground based on an answer in Stackoverflow.
var loader = new THREE.TextureLoader();
loader.load('Textures/Ground128.jpg',
function (texture) {
var groundGeometry = new THREE.PlaneBufferGeometry(2000, 2000, 100, 100);
const groundMaterial = new THREE.MeshLambertMaterial({map: texture});
var ground = new THREE.Mesh(groundGeometry, groundMaterial);
ground.receiveShadow = true; //Illumination addition
ground.rotation.x = -0.5 * Math.PI; // rotate into the horizontal.
scene.add(ground);
renderer.render(scene, camera); // <--- add this line
}
);

Add object and immediately take snapshot of canvas - three.js

I have a three.js scene with an object.
I let the user take a snapshot of what is painted on the canvas.
Although, I want all the snapshots to have also an other object. This object will never appear on the canvas though. So I thought that I will have this object in my scene, but I will position it very far so it will never be visible. But when the user clicks the link to download the snapshot, I will bring the object for some miliseconds in a position where is visible, and when the snapshot of the canvas is done I will move it again vary far.
document.getElementById('download').addEventListener('click', function() {
appearMesh();
downloadCanvas(this , "screenshot");
disappearMesh();
}, false);
function downloadCanvas(link, filename) {
link.href = document.getElementsByTagName("canvas")[0].toDataURL();
link.download = filename;
};
That doesn't work though : http://jsfiddle.net/95t964o0/21/
Nothing appears in the image.
Any ideas?
thanks
I think you should call a render after you move the object:
function appearMesh(){
meshToAppear.position.x = 0;
renderer.render( scene, camera );
}
function disappearMesh(){
meshToAppear.position.x = 1000;
renderer.render( scene, camera );
}

How can I change the texture in a Blender model loaded into three.js, after it's been loaded, with ImageUtils.loadTexture?

I'm doing a student project at involves a gift box where users can change how it looks.
I started learning what to do by making a cube, importing a texture and setting a gui.dat control to allow the user to change the texture.
I'm now trying to replace the cube with a blender model of a gift box but I'm having trouble changing the texture.
EDIT: The full code is on github here:
https://github.com/GitKiwi/GiftBox/blob/master/Workspace/Proto%208c%20Changing%20textures%20on%20giftbox.html
The coding for the working cube model is:
`// add cube with texture
var cubeGeometry = new THREE.CubeGeometry(4,4,4);
var cubeMaterial = new THREE.MeshLambertMaterial({ map:
THREE.ImageUtils.loadTexture("birthday.jpg") });
var cube = new THREE.Mesh(cubeGeometry,cubeMaterial);
cube.position.set (0,0,0);
cube.rotation.set (0,-1.2,0);
cube.receiveShadow = true;
// add the cube to scene
scene.add(cube); `
//gui texture change
`var controls = new function()
{ this.changeTexture = "birthday";
this.changeTexture = function (e){
var texture = THREE.ImageUtils.loadTexture
("../assets/textures/general/" + e + ".jpg");
cube.material.map = texture; }`
//gui control
var gui = new dat.GUI();
gui.add(controls, "changeTexture", ['christmas', 'valentine', 'birthday']).onChange(controls.changeTexture);
I'm loading the gift box in four parts and I'm just trying to get the first part, the box, to change texture. I load it with:
var box;
var loaderOne = new THREE.JSONLoader();
loaderOne.load('../assets/models/box.js', function (geometry)
{
var material = new THREE.MeshLambertMaterial({color: 0xffff00});
box = new THREE.Mesh(geometry, material);
box.position.set (5,0,5);
box.scale.set (1,1,1);
//box.name = "mybox";
scene.add(box);
});
I can't get it to change texture with the gui control. I've tried changing the "cube" to "box" in the gui texture change code and I've tried naming the box and calling it(commented out in the code above) but those didn't work. I've searched for answers to this in a number of places but I'm just really stuck. I feel I'm perhaps missing something obvious?
Any help to would really be appreciated.
The code wasn't working because there were no texture maps for the model I was importing.
What I did was go back to Blender and create a model with two textures that could each be applied to the whole model. The exported JSON file then had the model geometry and the two textures (with their texture maps).
In three.js I loaded it:
// load in geometry and textures
var loader = new THREE.JSONLoader();
loader.load('../models/two textures on cube.js', function (geometry, material)
{
matOne = new THREE.MeshLambertMaterial(material[1]);
matTwo = new THREE.MeshLambertMaterial(material[2]);
box = new THREE.Mesh(geometry, matOne);
//position, scale
box.position.set (0,0,0);
box.rotation.set (0,-1.2,0);
box.scale.set (2,2,2);
box.receiveShadow = true;
scene.add(box);
}, '../models');
and then used this code to switch the textures:
//gui control panel
var controls = new function()
{
//changing the texture
this.changeTexture = function (e)
{
switch (e)
{
case "birthday":
box.material = matOne;
break;
case "christmas":
box.material = matTwo;
break;
}
}
}
with this code for the gui.dat controls:
//gui control panel
var gui = new dat.GUI();
gui.add(controls, "changeTexture", ['birthday', 'christmas']).onChange(controls.changeTexture);

ThreeJS: Creating a background image that exactly fits the window?

In ThreeJS (JavaScript/ WebGL) how can I create a static background image that is part of the scene but resizes to fit the full inner browser window exactly? It works when I use CSS but then the background image won't show when making a "screenshot" via renderer.domElement.toDataURL('image/png'), which I want to. Thanks!
You can use a separate background scene to render the background image.
var bg = new THREE.Mesh(
new THREE.PlaneGeometry(2, 2, 0),
new THREE.MeshBasicMaterial({map: backgroundTexture})
);
// The bg plane shouldn't care about the z-buffer.
bg.material.depthTest = false;
bg.material.depthWrite = false;
var bgScene = new THREE.Scene();
var bgCam = new THREE.Camera();
bgScene.add(bgCam);
bgScene.add(bg);
Then in your render loop, draw bgScene before your real scene.
renderer.autoClear = false;
renderer.clear();
renderer.render(bgScene, bgCam);
renderer.render(scene, cam);
It wasn't clear for me if you are trying to make a panorama viewer or something like that...
If that was your goal, here's an answer I gave to solve the problem of inserting an equirectangular image to the rendered sphere (which can be controlled by mouse and/or deviceOrientation[accelerometer in smartphones]):
https://stackoverflow.com/a/37129356/1920145

Resources