I'm trying to create two scenes on two different canvases. Is it possible in Three.js?
var scene1 = new THREE.Scene()
var scene2 = new THREE.Scene()
scene1.add(camera1)
scene2.add(camera2)
...
renderer.render(scene1, camera1)
renderer.render(scene2, camera2)
Will it work like that?
Yes - it is totally possible, but the renderer-instance is always bound to the WebGLContext of the canvas. So you need to create create a renderer for every canvas you have. So this would be
renderer1.render(scene1, camera1);
renderer2.render(scene2, camera2);
(the other way around works as well: you can use multiple renderers to render the same scene with different cameras)
EDIT BASED ON COMMENTS
You can also render multiple scenes into different regions of the same canvas, using just one renderer. For this you need to setup a different viewport and scissor-test for every scene like this (based on https://threejs.org/examples/#webgl_multiple_views)
// first, render scene normally:
camera.aspect = totalWidth / totalHeight;
camera.updateProjectionMatrix();
renderer.setViewport(0, 0, totalWidth, totalHeight);
renderer.setScissorTest(false);
renderer.render( scene1, camera1 );
// then, render the overlay
renderer.setViewport(left, bottom, width, height);
renderer.setScissor(left, bottom, width, height);
renderer.setScissorTest(true);
renderer.setClearColor(view.background);
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.render( scene2, camera2 );
Related
Hello Community,
I am New in Three Js.I am Creating 2D Game With Three JS and I am facing Some issue to make Game Responsive and also when Size of the game play is decrease some functionalities are not working properly like touch event on object.I want to know that can we apply css to the three js objects so that we can create the responsive desing game.
Please Guide me about it.
Initialize your camera and renderer to the window size from the start and then add an event listener that will alter properties of objects that relate to the screen size. Usually something like this:
// keep track of the window size in an object
const size = { width: window.innerWidth, height: window.innerHeight };
// initialize camera based on recorded sizes
const camera = new THREE.PerspectiveCamera(
75,
size.width / size.height,
0.1,
100
);
camera.position.set(...);
scene.add(camera);
// initialize renderer based on recorded sizes
const renderer = new THREE.WebGLRenderer({ canvas });
renderer.setSize(size.width, size.height);
renderer.setPixelRatio(Math.min(2, window.devicePixelRatio));
// adjust relevant properties on window size change
window.addEventListener('resize', () => {
size.width = window.innerWidth;
size.height = window.innerHeight;
camera.aspect = size.width / size.height;
camera.updateProjectionMatrix();
renderer.setSize(size.width, size.height);
renderer.setPixelRatio(Math.min(2, window.devicePixelRatio));
});
Hopefully this is the answer you're looking for.
I'm having an issue when rendering a white material in ThreeJS version 87.
Here are the steps to replicate:
A white PNG image that is loaded as texture
This texture is used to create a MeshBasicMaterial (passed as parameter map)
The MeshBasicMaterial is used along a plane Geometry to create a Mesh
The Mesh is added to an empty Scene and rendered on a WebGLRenderer with alpha: true and clearColor as white
The problem is that the rendered texture now has grey edges on parts that should be fully white.
This happens with any image with white edges. I've also tried many different configurations for the renderer and the material but to no avail.
I've made a very simple CodePen that replicates the behavior as simple as possible. Does anyone know how can this problem be solved?
CodePen:
https://codepen.io/ivan-i1/pen/pZxwZX
var renderer, width, height, scene, camera, dataUrl, threeTexture, geometry, material, mesh;
width = window.innerWidth;
height = window.innerHeight;
dataUrl = '//data url from image';
threeTexture = new THREE.ImageUtils.loadTexture(dataUrl);
material = new THREE.MeshBasicMaterial({
map: threeTexture,
transparent: true,
alphaTest: 0.1
});
material.needsUpdate = true;
geometry = new THREE.PlaneGeometry(5, 5);
mesh = new THREE.Mesh(geometry, material);
mesh.position.z = -5;
scene = new THREE.Scene();
scene.add(mesh);
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 );
renderer = new THREE.WebGLRenderer({
alpha: true
});
document.body.appendChild( renderer.domElement );
renderer.setSize(width, height);
renderer.setClearColor( 0xffffff, 1 );
//renderer.render(scene, camera);
function render() {
//Finally, draw to the screen
requestAnimationFrame(render);
renderer.render(scene, camera);
}
render();
Any help is truly appreciated.
ThreeJS/87
Edit:
I think I'm lacking more precision on my post.
This is the original full alpha image:
It might not show because its all white
And this is the same image with different transparencies on 4 quadrants:
This one too might not show because its all white
I got a helpful answer where I was told to make the alphaTest higher, but the problem is that doing that wipes out the transparent parts out of the images, and I need to conserve those parts.
Here is a copy of the codepen with the updated images and showing the same (but slight) grey edges:
codepen
Sorry for not being as precise the first time, any further help is even more appreciated.
Set alphaTest to 0.9.. or higher.. observe the improvement.
Your star texture has gray or black in the area outside the star, which is why you're seeing a gray halo. You can fix it by filling the image with white, (but not changing the alpha channel) in your image editing tool.
Also, you should upgrade to latest three.js (r95)
edit:
I'm not sure what your exact expectation is.. but there are many different settings that control alpha blending in THREE. There is renderer.premultipliedAlpha = true/false (defaults to true) and material.transparent = true/false; material.alphaTest is a threshold value to control at what level alpha is ignored completely. There are also the material.blending, .blendEquation .blendEquation, .blendEquationAlpha, blendDst and blendSrc. etc. etc. You probably need to read up on those.
https://threejs.org/docs/#api/materials/Material
For instance.. here is your texture with:
renderer.premultipliedAlpha = false;
notice the black border on one quadrant of your texture.
https://codepen.io/manthrax/pen/KBraNB
I am adding augmented reality experience to my web app which originally created using threejs
I have a compound object(which is an Object3D instance with multiple meshes). but placing it into A-Frame giving unexpected flickering s shown in below
Pic of the original web app with threejs is given below
I have the three.js code like below
scene = new THREE.Scene();
mainObj = new THREE.Object3D();
scene.add(mainObj);
renderer = new THREE.WebGLRenderer({alpha: true, antialias: true});
renderer.sortObjects = false
container = document.getElementById("canvas-container");
width = $(container).innerWidth();
height = $(container).innerHeight();
renderer.setSize(width, height);
container.appendChild(renderer.domElement);
camera = new THREE.PerspectiveCamera(75, width / height, 10, 2000);
camera.position.set(0, 67, 100);
controls = new THREE.OrbitControls( camera , container);
controls.dampingFactor = 0.2;
controls.enableDamping = true;
controls.target.set( 0, 10, -20 );
controls.maxPolarAngle = (Math.PI/2) - 0.05;
controls.maxDistance = 800;
controls.minDistance = 2;
controls.target.set(0, buildingConfig.h/2, buildingConfig.l/-2)
controls.enableKeys = false;
controls.update();
scene.add(camera);
light = new THREE.HemisphereLight(0xffffff, 0xffffff, 0.7);
light.position.set(1, 10000, 1);
light.castShadow = true
scene.add( light );
renderer.render(scene, camera);
// logic to add child meshes to mainObj
Which I changed to include in A-Frame.
<script type="text/javascript">
initmodels();
AFRAME.registerComponent('e1', {
init:function(){
this.el.setObject3D('building', mainObj);
}
});
</script>
<a-scene e1>
</a-scene>
I guess this issue is related to the scene or renderer. Can anyone help me with a proper scene or renderer setup in A-Frame
This looks like z-fighting. Is the three.js version running on a different system than your aframe version?
Different platforms have different z-buffer precision. It may require you to make changes to the geometry to compensate for the limited resolution.
Also, I don't know about AR.s, but the THREE renderer has a "logarithmicDepthBuffer" option that can increase the resolution of your z-buffer at near scales, but may have some side effects.
I had exactly the same issue. After a few trial and errors, I was able to fix it
Added recent version of aframe
Add <a-scene embedded artoolkit='sourceType: webcam;' renderer='logarithmicDepthBuffer: true;'>
Add <a-marker-camera camera="far:100000; near:0.01" >
Main reason was the light, Remove all lights and add only the hemisphere light into the scene and improvise upon other lights later on.
Hope this would resolve your issue too.
I'm trying to have text sprites in the 3d scene with constant size (regardless of camera distance) using a PerspectiveCamera. In order to get non-sprites to have constant size, I make them children of a special "scaled" object which adjusts its scale as the camera distance to origin changes (see the code below). This works well to keep a general object roughly the same visual size, but when I add a sprite to the scaled object, the sprite seems to ignore its parent's scale (so it gets smaller and bigger as you zoom out and in).
Interestingly, when we switch to an orthographic camera (uncomment the appropriate line below), this special scaled object doesn't seem to affect children anymore (i.e., children don't stay a constant size). However, since we have an orthographic camera, sprites no longer scale as the camera distance changes (so they maintain a constant size), but this is independent of the scaled object.
I notice a few other similar questions and answers, including adjust the scale of the sprites themselves (it seems much easier to add all my sprites to a single scaling object), use an orthographic camera overlay to draw sprites (see also this) (but I want my sprites to be inside the 3d perspective scene).
So, my questions are: why do sprites not use scale according to their parent's scale when using a PerspectiveCamera? Also, why does my scaled object not work with the orthographic camera? Are these bugs or features of the cameras?
Thanks!
http://jsfiddle.net/LLbcs/8/
var camera, scene, renderer, geometry, material, mesh, text, controls;
init();
animate();
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 10000); var scenescale=1;
//camera = new THREE.OrthographicCamera( -7,7,7,-7, 1, 20 );
camera.position.z = 10;
scene.add(camera);
scaled=new THREE.Object3D();
scene.add(scaled);
var textmaterial = new THREE.SpriteMaterial( {color: 'red', useScreenCoordinates: true, map: texttexture("hi")});
text = new THREE.Sprite( textmaterial );
text.position.set( 1, 1, 0);
scaled.add(text);
var geometry = new THREE.BoxGeometry( 1, 1,1 );
var material = new THREE.MeshLambertMaterial( { color: 0xffffff } );
mesh = new THREE.Mesh( geometry, material );
mesh.position.set(0,3,0);
scaled.add(mesh);
var light = new THREE.PointLight('green');
light.position.set(10,15,10);
camera.add(light);
light = new THREE.PointLight(0x333333);
light.position.set(-10,-15,-8);
camera.add(light);
renderer = new THREE.WebGLRenderer();
controls = new THREE.OrbitControls( camera, renderer.domElement );
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
}
function animate() {
requestAnimationFrame(animate);
var scale = camera.position.length()/10;
scaled.scale.set(scale,scale,scale);
render();
}
function render() {
renderer.render(scene, camera);
}
function texttexture(string) {
var fontFace = "Arial"
var size = "50";
var color = "white"
var squareTexture = true;
var canvas = document.createElement("canvas");
var context = canvas.getContext("2d");
canvas.height = size;
var font = "Normal " + size + "px " + fontFace;
context.font = font;
var metrics = context.measureText(string);
var textWidth = metrics.width;
canvas.width = textWidth;
if (squareTexture) {
canvas.height = canvas.width;
}
var aspect = canvas.width / canvas.height;
context.textAlign = "center";
context.textBaseline = "middle";
context.fillStyle = color;
// Must set the font again for the fillText call
context.font = font;
context.fillText(string, canvas.width / 2, canvas.height / 2);
var t = new THREE.Texture(canvas);
t.needsUpdate = true;
return t;
}
If you want text to appear over a 3D scene and you don't care if it is static, why not try layering a div over the scene instead?
This will allow you to save graphics bandwidth and memory, improving performance of your scene and give you much better flexibility over what you display. It's also much easier to do and to maintain.
Note: I want to avoid modifying the model in the javascript code and do all the model design inside Blender.
Note #2: While this question is long, it is actually a basic problem (title says it all). The below is "walk-through" to the problem.
I am trying export Blender models to threejs.org as DAE model but have problem with models with texture (I have tried JSON and OBJ+MTL format too):
To make things simpler, here are the steps I perform (and fail) to add texture to simple "Startup file" which contains a cube, camera, and light:
Select the cube
In the Materials panel, make sure the default Material for the cube is selected.
In the Texture panel, make sure "Tex" (the default texture for the material) is selected.
For this texture, set Type to "Image or Movie"
In the Image section of panel, open a grass1.jpg (a 512x512 image) as the texture.
In the Mapping section, change the Coordinates to UV.
Export the model as Collada model, checking "Include UV Textures", "Include Material Textures", and "Copy" checkboxes.
You can download blend, dae, and texture file mentioned in these steps.
Then I use the following code to load the DAE model, but I get this error and the cube is not shown:
256 [.WebGLRenderingContext]GL ERROR :GL_INVALID_OPERATION :
glDrawElements: attempt to access out of range vertices in attribute 2
WebGL: too many errors, no more errors will be reported to the console for this context.
<script src="js/three.min.js"></script>
<script src="js/OrbitControls.js"></script>
<script src="js/ColladaLoader.js"></script>
<script>
var scene, camera, renderer;
init();
animate();
function init() {
scene = new THREE.Scene();
var WIDTH = window.innerWidth,
HEIGHT = window.innerHeight;
renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setSize(WIDTH, HEIGHT);
document.body.appendChild(renderer.domElement);
camera = new THREE.PerspectiveCamera(45, WIDTH / HEIGHT, 0.1, 10000);
camera.position.set(10,10,10);
scene.add(camera);
window.addEventListener('resize', function() {
var WIDTH = window.innerWidth,
HEIGHT = window.innerHeight;
renderer.setSize(WIDTH, HEIGHT);
camera.aspect = WIDTH / HEIGHT;
camera.updateProjectionMatrix();
});
var loader = new THREE.ColladaLoader();
loader.load( 'models/untitled.dae', function(geometry) {
dae = geometry.scene;
scene.add(dae);
var gridXZ = new THREE.GridHelper(100, 10);
gridXZ.setColors( new THREE.Color(0x8f8f8f), new THREE.Color(0x8f8f8f) );
gridXZ.position.set(0,0,0);
scene.add(gridXZ);
});
controls = new THREE.OrbitControls(camera, renderer.domElement);
}
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
controls.update();
}
</script>
And here is the screenshot of Blender after mentioned 7 steps:
Update: Exporting as js file using JSON exporter for Blender doesn't work either and resulted the very same error.
Update 2: Same error after exporting to OBJ+MTL and loading them with OBJMTLLoader.
The problem is you have not set up UV coordinates for your model. By default, each face applies the whole texture, but in blender the UVs are blank when exporting.
You want to specifically set up your UV coordinates. These are coordinates that show how to apply a texture to each face.
Make sure to UV unwrap your model in blender. Go to edit mode (tab), select all faces, press "u", and click "unwrap". Then try to re-export.
Unwrap is just 1 method, there are many. Experiment with different methods in blender to get the results you want (possibly the "reset" option).