I have been doing some experiments with three.js. However, when I try to do a simple test, I can't get it to display anything. Here's my code. If someone could tell me what I'm missing it would be really helpful.
//Constant declaration
var RENDER_DIST = 1000,
FOV = 75;
var WIDTH = window.innerWidth,
HEIGHT= window.innerHeight;
//Create the scene
var scene = new THREE.Scene();
//Create the camera
var camera = new THREE.PerspectiveCamera(FOV, WIDTH / HEIGHT, 0.1, RENDER_DIST);
//Pull the camera back a bit
camera.z = 100;
//Then add it to the scene
scene.add(camera);
//Create a renderer
renderer = new THREE.WebGLRenderer();
renderer.setSize(WIDTH,HEIGHT);
renderer.domElement.className = "glMain";
//Container is a div
$("#container").html(renderer.domElement);
//Boilerplate done! Celebrate!
(function init() {
var geometry = new THREE.SphereGeometry(50);
var material = new THREE.MeshBasicMaterial({color: 0xff0000});
var sphere = new THREE.Mesh(geometry, material);
scene.add(sphere);
//debugging
console.log("Sphere at " + sphere.position.x + " " + sphere.position.y + " " + sphere.position.z);
})();
//Our main function
(function loopRun() {
requestAnimationFrame(loopRun);
console.log("rendered");
renderer.render(scene, camera);
})();
On the console log I am getting all the "rendered" messages but nothing is displaying. I have checked that the canvas is the right size and it is, so I have no idea what is wrong. I have tried a few different geometries.
EDIT: I am using Chrome, and online three.js examples work fine. There are no errors on the console log.
//Pull the camera back a bit
camera.position.z = 100;
//Container is a div
document.body.appendChild(renderer.domElement);
you can also try :
$("#container").append(renderer.viewElement);
Related
I'm using three.js and a script similar to OrbitControls as my controller. In my main.js file I have a THREE.Group() that is being passed to the controller as an argument. From there, I'm attempting to rotate the entire group.
Problem 1: once the group is passed to the controller, I can no longer access its properties without making a copy
Problem 2: a copy does not contain the entire THREE.Group(), rather only the first child
I've been working on this for hours now and I've tried about 50 different things including anything relevant on stackoverflow. I'm completely out of ideas on how to combat this problem.
main.js
let container;
let camera;
let controls;
let game;
let renderer;
let scene;
function init() {
container = document.querySelector('#scene-container');
scene = new THREE.Scene();
const fov = 35;
const aspect = container.clientWidth / container.clientHeight;
const near = 0.1;
const far = 100;
camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
//***** This is the important line ******
controls = new THREE.ObjectControls(camera, container, game);
game = new THREE.Group();
scene.add(game);
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial();
var mesh1 = new THREE.Mesh(geometry, material);
game.add(mesh1);
var mesh2 = new THREE.Mesh(geometry, material);
mesh2.position.set(0,1,0);
game.add(mesh2);
renderer = new THREE.WebGLRenderer();
renderer.setSize(container.clientWidth, container.clientHeight);
renderer.setPixelRatio(window.devicePixelRatio);
container.appendChild(renderer.domElement);
renderer.setAnimationLoop(() => {
renderer.render(scene, camera);
});
}
init();
ObjectControls.js
THREE.ObjectControls = function (camera, domElement, objectToMove) {
mesh = objectToMove;
domElement.addEventListener('mousemove', mouseMove, false);
function mouseMove(e) {
//** objectToMove is undefined :( **
mesh.rotation.y += 3;
}
};
Expected result is that the entire THREE.Group() game will be rotated, but the result that I get is that only the first child of game is rotated, in this case mesh1.
controls = new THREE.ObjectControls(camera, container, game);
game = new THREE.Group();
There is an error in your code since you pass the undefined variable game to the ctor of ObjectControls. If you assign a new object to game one line later, ObjectControls does not have a reference to this variable.
The idea is to assign the group object to game first and then create ObjectControls. You essentially switch both lines.
three.js R105
In Three.js, the value for setClearColor is white But it render black, when i call external html file:
enter image description here
External file codes:
<div id="3d-modal"></div>
<script src="juicer/js/three.js"></script>
3D-modal scripts:
<script>
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75,
window.innerWidth/window.innerHeight, 0.1, 1000);
var renderer = new THREE.WebGLRenderer({antialias : true});
// renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0xffffff);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
// Appending Webgl to the "container" Div...
// document.body.appendChild( renderer.domElement );
var container = document.getElementById("3d-modal");
var canvas_width = 290;
var canvas_height = 165;
var renderer = new THREE.WebGLRenderer();
renderer.setSize(canvas_width , canvas_height);
container.appendChild(renderer.domElement);
var animate = function () {
requestAnimationFrame( animate );
renderer.render(scene, camera);
};
animate();
</script>
How can i solve this?
I came across this when I started using three.js as well. It's actually a javascript issue:
Update: Thanks to HdN8 for the updated solution:
renderer.setClearColor( 0xffffff, 0);
(note: syntax => setClearColor ( color, alpha ))
Update #2: As pointed out by WestLangley in another similar question - you must now use the below code when creating a new WebGLRenderer instance in conjunction with the setClearColor() function:
var renderer = new THREE.WebGLRenderer({ alpha: true });
Update #3: Mr.doob points out that since r78 you can alternatively use the code below to set your scene's background colour:
var scene = new THREE.Scene(); // initialising the scene
scene.background = new THREE.Color( 0xff0000 );
Update #4: G Dog
If the background color doesn't change, try changing alpha to 1 from 0.
Today I've been experimenting with building my first ever skybox in three.js. I've read a lot of tutorials and the code I've ended up with is based on this one: http://learningthreejs.com/blog/2011/08/15/lets-do-a-sky/
I did make a few changes in order to allow for the images to load first, and to make it compatible with the version of three.js which I am using.
I've overcome a lot of small problems to get to the point I am currently at, but cannot find any answer to my current issue despite having searched quite hard. My problem is that despite using purpose-built skybox textures downloaded from the internet, it is glaringly obvious that my skybox is a cube with corners and edges. The textures appear heavily distorted and are not at all convincing.
Here is a screenshot of how my skybox looks:
And here is a link to the site from which I downloaded the images:
http://www.humus.name/index.php?page=Cubemap&item=Yokohama3
As you can see, in their preview it looks much better.
I've tried this with a few different downloaded textures and every time it is very obvious that you are looking at the inside of a cube.
Here's my code (I'm including all my code, not just the section which creates the skybox):
var scene;
var camera;
var renderer;
function createRenderer () {
renderer = new THREE.WebGLRenderer();
renderer.setClearColor(0x000000, 1.0)
renderer.setSize(window.innerWidth, window.innerHeight)
renderer.shadowMapEnabled = true;
//renderer.shadowCameraNear = 0.5;
//renderer.shadowCameraFar = 500;
}
function createCamera () {
camera = new THREE.PerspectiveCamera(
45,
window.innerWidth/window.innerHeight,
0.1, 1000
);
camera.position.x = 50;
camera.position.y = 30;
camera.position.z = 40;
camera.lookAt(scene.position);
}
function createPlane () {
var material = new THREE.MeshLambertMaterial({
color: 0xcccccc,
})
var geometry = new THREE.PlaneGeometry(40, 40)
var plane = new THREE.Mesh(geometry, material)
plane.receiveShadow = true;
plane.rotation.x = -Math.PI/2
plane.position.y = -6;
scene.add(plane)
}
function createLight () {
var spotLight = new THREE.DirectionalLight(0xffffff);
spotLight.position.set( 0, 50, 20 );
spotLight.shadowCameraVisible = true;
spotLight.shadowDarkness = 0.5
spotLight.shadowCameraNear = 0;
spotLight.shadowCameraFar = 100;
spotLight.shadowCameraLeft = -50;
spotLight.shadowCameraRight = 50;
spotLight.shadowCameraTop = 50;
spotLight.shadowCameraBottom = -50;
spotLight.castShadow = true;
scene.add(spotLight);
}
function createSkyboxAndSphere () {
var urlPrefix = "Yokohama3/";
var urls = [ urlPrefix + "posx.jpg", urlPrefix + "negx.jpg",
urlPrefix + "posy.jpg", urlPrefix + "negy.jpg",
urlPrefix + "posz.jpg", urlPrefix + "negz.jpg" ];
var textureCube = THREE.ImageUtils.loadTextureCube( urls , undefined, function () {;
var shader = THREE.ShaderLib["cube"];
var uniforms = THREE.UniformsUtils.clone( shader.uniforms );
shader.uniforms['tCube'].value = textureCube; // textureCube has been init before
var material = new THREE.ShaderMaterial({
fragmentShader : shader.fragmentShader,
vertexShader : shader.vertexShader,
uniforms : shader.uniforms,
depthWrite : false,
side: THREE.BackSide,
});
var geometry = new THREE.BoxGeometry(100, 100, 100)
var skybox = new THREE.Mesh(geometry, material)
scene.add(skybox)
var material = new THREE.MeshPhongMaterial({
color: "red",
envMap: textureCube,
reflectivity: 0.3,
})
var geometry = new THREE.SphereGeometry(6, 30, 15)
var sphere = new THREE.Mesh(geometry, material)
sphere.castShadow = true;
sphere.receiveShadow = true;
scene.add(sphere)
});
}
function init () {
scene = new THREE.Scene();
createRenderer();
createCamera();
createLight();
createPlane ();
createSkyboxAndSphere ();
document.getElementById("container").appendChild(renderer.domElement)
render ()
}
function render () {
renderer.render(scene, camera)
requestAnimationFrame(render);
}
window.onload = function () {
init ();
}
I suspect I am fundamentally misunderstanding something about how cubemapping and skyboxes work - I am very new to this in particular and javascript in general and am aware of huge gaps in my knowledge.
My apologies if the answer to this is obvious and/or the question has been asked before, and a pre-emptive thanks for your help!
Your camera needs to be in the center of the skybox -- or at least near the center.
So either move your camera very close to the box center, or update the box position every frame to match the camera position.
Or make the skybox much bigger relative to the camera offset from the origin.
Or place the skybox in a separate scene and have two cameras and two render passes, as in this example.
three.js r.74
In my three.js project I use a high z position for my camera.
When the z position is too high my scene becomes black.
So, when I zoom out it becomes black. But I don't want that to happen.
This is how it is with camera.position.z = 3000;
And when I zoom out, just one zoom, it is like this:
For the controls I use OrbitControls, My camera is like:
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 3000);
camera.position.z = 3000;
And here the code for the planet and some planets' orbits:
var scene = new THREE.Scene();
var material = new THREE.MeshLambertMaterial({
map: THREE.ImageUtils.loadTexture("assets/img/sun.jpg")
});
var sun = new THREE.Mesh(new THREE.SphereGeometry(200, 50, 50), material);
scene.add(sun);
var orbitLine = function(radius,y)
{
var segments = 64,
line_material = new THREE.LineBasicMaterial( { color: 0xffffff } ),
geometry = new THREE.CircleGeometry( radius, segments );
geometry.vertices.shift();
var orbit = new THREE.Line( geometry, line_material );
if(y)
orbit.position.y=y;
else if(!y)
orbit.position.y=0;
scene.add(orbit);
};
var Mercury_orbit = orbitLine(400,-70);
var Venus_orbit = orbitLine(700,70);
var Earth_orbit = orbitLine(900,70);
var Mars_orbit = orbitLine(1250,70);
var Jupiter_orbit = orbitLine(3000,70);
Couldn't provide a fiddle as for some reason it didn't work.
If you need more code tell me in the comments and I will add it.
Any ideas?
thanks.
Your camera's far plane is at 3000 which means everything that is 3000 units away will be clipped and not drawn.
At the same time you have placed your camera at (0,0,3000) so you are right on the position where things will start to disappear.
i'm new in three.js and have a problem by scaling a object. I already looked at the documentation (https://github.com/mrdoob/three.js/wiki/Updates), but i don't really understand it at all.
My Problem: By changing a HTML-select-element the CubeGeometry should be scaled in the x-direction. That is already working BUT the "old" Cube do not disappear. So i have 2 Cubes. But i want only one Cube with the current size. I hope you can understand my problem ;-)
So here is my Code from the View:
$(document).on('change',".configurator > form select",function(event){
// update 3D-object - is that a nice way???
$.getScript("/javascripts/3D-animation.js.erb", function(){
// here comes the update
OBJECT3D.updateObject();
});
})
And here is my 3D-animation.js.erb:
var drawing_area;
var renderer;
var camera;
var obj;
var scene;
var OBJECT3D = {};
$(function() {
// get drawing_area
drawing_area = document.getElementById("canvas_wrapper");
// initialize renderer
renderer = new THREE.WebGLRenderer();
renderer.setSize(drawing_area.clientWidth, drawing_area.clientHeight);
renderer.setClearColor( 0xffffff, 1);
// add renderer to drawing_area
drawing_area.appendChild(renderer.domElement);
// initialize camera
camera = new THREE.PerspectiveCamera(45, drawing_area.clientWidth/drawing_area.clientHeight, 1, 100000);
camera.position.z = 1000;
camera.position.y = 100;
camera.position.x = 300;//-0.78;
// create texture
var texture = THREE.ImageUtils.loadTexture( "/images/materials/texture_1.jpg" );
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set( 1, 1 );
// create object
var obj_form = new THREE.CubeGeometry(250,250,250);
var obj_material = new THREE.MeshLambertMaterial( { map: texture,ambient: 0x999999 } );
OBJECT3D.obj = new THREE.Mesh(obj_form, obj_material);
// so what do i need here?
OBJECT3D.obj.geometry.dynamic = true;
// OBJECT3D.obj.geometry.__dirtyVertices = true;
// OBJECT3D.obj.geometry.__dirtyNormals = true;
// OBJECT3D.obj.geometry.verticesNeedUpdate = true;
// create scene
scene = new THREE.Scene();
scene.add(camera);
scene.add(OBJECT3D.obj);
// create lights
pointLight = new THREE.PointLight(0xFFFFFF);
pointLight.position.x = 400;
pointLight.position.y = 200;
pointLight.position.z = 1300;
scene.add(pointLight);
ambientLight = new THREE.AmbientLight( 0xffffff);
scene.add( ambientLight );
requestAnimationFrame(render);
function render(){
requestAnimationFrame(render);
OBJECT3D.obj.rotation.y += 0.005;
OBJECT3D.obj.rotation.z += 0.005;
renderer.render(scene, camera);
};
// update object
OBJECT3D.updateObject = function () {
console.log("in update");
OBJECT3D.obj.scale.x = 2.5; // SCALE
OBJECT3D.obj.geometry.needsUpdate = true;
//render();
}
});
Sorry, if the Code is not the best one, but i'm really new in this stuff! :) hope you can help me!
Thanks!
I think it is because you are using $.getScript method. This will load your script each time again and create a new instance of OBJECT3D.
I propose that you make sure that your code in 3D-animation.js.erb will be included and called only once upon the load of a page (include it just like any other regular javascript file) and then call your update directly like this:
$(document).on('change',".configurator > form select", function(event) {
OBJECT3D.updateObject();
});
also, I believe you can drop following lines of code:
OBJECT3D.obj.geometry.needsUpdate = true;
and
OBJECT3D.obj.geometry.dynamic = true;