Texture applied only on canvas click with Three.js - three.js

I am using WebGLRenderer from Three.js to render an object reconstructed from an IndexedFaceStructure that has texture. My problem is that when the page loads the object shows up with no texture, only a black colored mesh displays, however, when i click on the canvas where i render the object the texture shows up.
I have been looking around and tried the texture.needsUpdate = true; trick, but this one removes also the black meshed object on page load so i am at a loss here.
These are the main bits of my code:
function webGLStart() {
container = document.getElementById("webgl-canvas");
renderer = new THREE.WebGLRenderer({canvas:container, alpha:true, antialias: true});
renderer.setClearColor(0x696969,1);
renderer.setSize(container.width, container.height) ;
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(45, container.width / container.height, 1, 100000);
camera.position.set(60, 120,2000) ;
//computing the geometry2
controls = new THREE.OrbitControls( camera );
controls.addEventListener( 'change', render );
texture = new THREE.ImageUtils.loadTexture(texFile);
//texture.needsUpdate = true;
material = new THREE.MeshBasicMaterial( {wireframe:false, map: texture, vertexColors: THREE.VertexColors} );
mesh = new THREE.Mesh(geometry2, material);
scene.add(mesh);
render();
animate();
}
function render()
{
renderer.render(scene, camera);
}
function animate()
{
controls.update();
}
And the html part: canvas id="webgl-canvas" style="border: none;" width="900" height="900" (i could not add it properly).
Do you happen to have a clue why is this happening?

If you have a static scene, you do not need an animation loop, and you only need to render the scene when OrbitControls modifies the camera position/orientation.
Consequently, you can use this pattern -- without an animation loop:
controls.addEventListener( 'change', render );
However, you also need to force a render when the texture loads. You do that by specifying a callback to render in the ImageUtils.loadTexture() method:
var texture = THREE.ImageUtils.loadTexture( "textureFile", undefined, render );
Alternatively, you could add the mesh to the scene and call render in the callback.
three.js r.70

Related

Three.js: Apply SSAO (Screen Space Ambient Occlusion) to Displacement map

have I've implemented the Screen Space Ambient Occlusion in my Three.js project correctly, and run perfect, like this:
//Setup SSAO pass
depthMaterial = new THREE.MeshDepthMaterial();
depthMaterial.depthPacking = THREE.RGBADepthPacking;
depthMaterial.blending = THREE.NoBlending;
var pars = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBAFormat, stencilBuffer: true }; //Stancilbuffer true because not effect transparent object
depthRenderTarget = new THREE.WebGLRenderTarget(window.innerWidth, window.innerHeight, pars);
depthRenderTarget.texture.name = "SSAOShader.rt";
ssaoPass = new THREE.ShaderPass(THREE.SSAOShader);
///////ssaoPass.uniforms[ "tDiffuse" ].value will be set by ShaderPass
ssaoPass.uniforms["tDepth"].value = depthRenderTarget.texture;
ssaoPass.uniforms['size'].value.set(window.innerWidth, window.innerHeight);
ssaoPass.uniforms['cameraNear'].value = camera.near;
ssaoPass.uniforms['cameraFar'].value = camera.far;
ssaoPass.uniforms['radius'].value = radius;
ssaoPass.uniforms['aoClamp'].value = aoClamp;
ssaoPass.uniforms['lumInfluence'].value = lumInfluence;
But, when I set a material with displacementMap (that run correctly without SSAO enabled), this is the result. Notice that the SSAO is applied "correctly" to the original sphere (with a strange-trasparent-artificat), but I need to apply it to the "displaced vertex" of the sphere)
This is my composer passes:
//Main render scene pass
postprocessingComposer.addPass(renderScene);
//Post processing pass
if (ssaoPass) {
postprocessingComposer.addPass(ssaoPass);
}
And this is the rendering loop with composer
if (postprocessingComposer) {
if (ssaoPass) {
//Render depth into depthRenderTarget
scene.overrideMaterial = depthMaterial;
renderer.render(scene, camera, depthRenderTarget, true);
//Render composer
scene.overrideMaterial = null;
postprocessingComposer.render();
renderer.clearDepth();
renderer.render(sceneOrtho, cameraOrtho);
}
else {
//Render loop with post processing (no SSAO, becasue need more checks, see above)
renderer.clear();
postprocessingComposer.render();
renderer.clearDepth();
renderer.render(sceneOrtho, cameraOrtho);
}
}
else {
//Simple render loop (no post-processing)
renderer.clear();
renderer.render(scene, camera);
renderer.clearDepth();
renderer.render(sceneOrtho, cameraOrtho);
}
How can i archive a correct Screen Space Ambient Occlusion applied to a mesh with Displacement Map? Thanks.
[UPDATE]:
After some work i tried to this procedure for every child in the scene, with displacement map, to define a new a new overrideMaterial of the scene equal to a depthMaterial with displacement map parameters of the child material.
var myDepthMaterial = new THREE.MeshDepthMaterial({
depthPacking: THREE.RGBADepthPacking,
displacementMap: child.material.displacementMap,
displacementScale: child.material.displacementScale,
displacementBias: child.material.displacementBias
});
child.onBeforeRender = function (renderer, scene, camera, geometry, material, group) {
scene.overrideMaterial = myDepthMaterial;
};
This solution sounds good, but doesnt work.
You are using SSAO with a displacement map. You need to specify the displacement map when you instantiate the depth material.
depthMaterial = new THREE.MeshDepthMaterial( {
depthPacking: THREE.RGBADepthPacking,
displacementMap: displacementMap,
displacementScale: displacementScale,
displacementBias: displacementBias
} );
three.js r.87

Function LookAt to turn around an object ?

as part of a project, I have to turn the camera around an object (position 0, 0,0) which remains to him still. For this, I want to know if the LookAt function is the one that is best suited , And also how does it work?
Integrating OrbitControls should be done with a few lines of code. So, the basic lines of code should be:
// init
var controls = new THREE.OrbitControls( camera, renderer.domElement );
controls.enableZoom = false; // optional
controls.enablePan = false; // optional
controls.center.set(0,0,0); // should be initially 0,0,0
controls.addEventListener( 'change', render ); // if you are not using requestAnimationFrame()
camera.position.z = 500; // should be bigger than the radius of your sphere
// render
function render() {
renderer.render(scene, camera);
}
<script src="js/controls/OrbitControls.js"></script>
Now, you should be able to rotate the camera around your sphere using your mouse.
All the other essential stuff (camera, renderer) can be found at the example: https://threejs.org/examples/#misc_controls_orbit

How to use rendering result of scene as texture in ThreeJS

I would like to use the rendering result of the scene as a texture in ThreeJS.
Does ThreeJS have such a function?
Do I need to modify ThreeJS?
Thanks.
You can render a scene to a texture by passing a THREE.WebGLRenderTarget to THREE.WebGLRenderer.render().
First, create a render target of the desired size (this is your texture) :
var renderer = new THREE.WebGLRenderer();
var renderTarget = new THREE.WebGLRenderTarget(512, 512);
You can then use THREE.WebGLRenderTarget.texture on a material :
var geometry = new THREE.PlaneGeometry(1.0, 1.0);
var material = new THREE.MeshBasicMaterial({
map: renderTarget.texture
});
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
Finally render the scene in 2 passes :
renderer.render(fakeScene, fakeCamera, renderTarget);
renderer.render(scene, camera);
You may want to create a new scene and a new camera to render on the renderTarget. It depends on what you want to do.
Take a look at this fiddle and this example.

Why does this ThreeJs plane appear to get a kink in it as the camera moves down the y-axis?

I have an instance of THREE.PlaneBufferGeometry that I apply an image texture to like this:
var camera, scene, renderer;
var geometry, material, mesh, light, floor;
scene = new THREE.Scene();
THREE.ImageUtils.loadTexture( "someImage.png", undefined, handleLoaded, handleError );
function handleLoaded(texture) {
var geometry = new THREE.PlaneBufferGeometry(
texture.image.naturalWidth,
texture.image.naturalHeight,
1,
1
);
var material = new THREE.MeshBasicMaterial({
map: texture,
overdraw: true
});
floor = new THREE.Mesh( geometry, material );
floor.material.side = THREE.DoubleSide;
scene.add( floor );
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, texture.image.naturalHeight * A_BUNCH );
camera.position.z = texture.image.naturalWidth * 0.5;
camera.position.y = SOME_INT;
camera.lookAt(floor.position);
renderer = new THREE.CanvasRenderer();
renderer.setSize(window.innerWidth,window.innerHeight);
appendToDom();
animate();
}
function handleError() {
console.log(arguments);
}
function appendToDom() {
document.body.appendChild(renderer.domElement);
}
function animate() {
requestAnimationFrame(animate);
renderer.render(scene,camera);
}
Here's the code pen: http://codepen.io/anon/pen/qELxvj?editors=001
( Note: ThreeJs "pollutes" the global scope, to use a harsh term, and then decorates THREE using a decorator pattern--relying on scripts loading in the correct order without using a module loader system. So, for brevity's sake, I simply copy-pasted the source code of a few required decorators into the code pen to ensure they load in the right order. You'll have to scroll down several thousand lines to the bottom of the code pen to play with the code that instantiates the plane, paints it and moves the camera. )
In the code pen, I simply lay the plane flat against the x-y axis, looking straight up the z-axis, as it were. Then, I slowly pan the camera down along the y-axis, continuously pointing it at the plane.
As you can see in the code pen, as the camera moves along the y-axis in the negative direction, the texture on the plane appears to develop a kink in it around West Texas.
Why? How can I prevent this from happening?
I've seen similar behaviour, not in three.js, not in a browser with webGL but with directX and vvvv; still, i think you'll just have to set widthSegments/heightSegments of your PlaneBufferGeometry to a higher level (>4) and you're set!

Three js - Referencing individual meshes in imported blender scene

I am new to three.js and I have a basic blender scene with 2 different meshes which I have also named. I have managed to import the meshes into three but I would like to know how to reference and manipulate each mesh? is it possible if the 2 meshes are in the same file or should I load mesh1.js, mesh2.js etc?
This is the code:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
</head>
<body style="margin: 0;">
<script src="https://rawgithub.com/mrdoob/three.js/master/build/three.js"></script>
<script src="js/OrbitControls.js"></script>
<script>
// Set up the scene, camera, and renderer as global variables.
var scene, camera, renderer;
init();
animate();
// Sets up the scene.
function init() {
// Create the scene and set the scene size.
scene = new THREE.Scene();
var WIDTH = window.innerWidth,
HEIGHT = window.innerHeight;
// Create a renderer and add it to the DOM.
renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setSize(WIDTH, HEIGHT);
document.body.appendChild(renderer.domElement);
// Create a camera, zoom it out from the model a bit, and add it to the scene.
camera = new THREE.PerspectiveCamera(45, WIDTH / HEIGHT, 0.1, 20000);
camera.position.set(0,6,0);
scene.add(camera);
// Create an event listener that resizes the renderer with the browser window.
window.addEventListener('resize', function() {
var WIDTH = window.innerWidth,
HEIGHT = window.innerHeight;
renderer.setSize(WIDTH, HEIGHT);
camera.aspect = WIDTH / HEIGHT;
camera.updateProjectionMatrix();
});
// Set the background color of the scene.
renderer.setClearColorHex(0x333F47, 1);
// Create a light, set its position, and add it to the scene.
var light = new THREE.PointLight(0xffffff);
light.position.set(-100,-200,100);
scene.add(light);
var light2 = new THREE.PointLight(0xffffff);
light2.position.set(-100,200,100);
scene.add(light2);
// Load in the mesh and add it to the scene.
var loader = new THREE.JSONLoader();
loader.load( "tree-land.js", function( geometry, materials ){
var material = new THREE.MeshFaceMaterial( materials );
mesh = new THREE.Mesh( geometry, material );
scene.add(mesh);
});
// Add OrbitControls so that we can pan around with the mouse.
controls = new THREE.OrbitControls(camera, renderer.domElement);
}
// Renders the scene and updates the render as needed.
function animate() {
requestAnimationFrame(animate);
// Render the scene.
renderer.render(scene, camera);
controls.update();
}
</script>
</body>
</html>
The mesh variable you have declared is an Object3D, which can be manipulated using all the methods and properties as seen in the documentation: http://threejs.org/docs/#Reference/Core/Object3D
It looks like the call to JSONLoader.load returns a single geometry and material via the callback, so would not seem to support loading multiple files in a single call or multiple geometries in a single file. You might want to take a look at some of the other loaders for that purpose. I have successfully used the ColladaLoader (not in the documentation). Blender exports to Collada as well. The code is in examples/js/loaders of the repository.

Resources