I am making a THREE.JS game for one of my classes. I am very keen to learn and understand THREE.JS so I followed some of their tutorials and learnt Javascript. I am more of a C# and C++ guy, so the following question may just the result of the lack of my understanding of Javascript.
I wrote the following Object oriented structure for the game.
ObjectEnum = {
Cube: 0,
Sphere: 1,
Cylinder: 2
}
Transform = function () {
var position, rotation, scale;
}
function TransformInit(position, rotation, scale) {
var t = new Transform();
t.position = position;
t.rotation = rotation;
t.scale = scale;
return t;
}
GameObject = function () {
var mesh, geometry, material, transform;
var GameObject = this;
this.init = function (ObjectEnumType, materialShader, transformVector3) {
if (ObjectEnumType == 0) {
geometry = new THREE.BoxGeometry(transformVector3.scale);
}
transform = transformVector3;
material = materialShader;
mesh = new THREE.Mesh(geometry, material);
}
this.getMesh = function () {
return mesh;
}
}
var go = new GameObject();
this.onload = function () {
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var t = TransformInit(new THREE.Vector3(10, 0, 0), new THREE.Vector3(10, 0, 0), new THREE.Vector3(1, 1, 1));
go.init(ObjectEnum.Cube, new THREE.MeshPhongMaterial({
specular: '#a9fcff',
color: '#00abb1',
emissive: '#006063',
shininess: 100
}), t);
var w = go.getMesh();
scene.add(w);
camera.position.z = 5;
console.log(t);
var render = function () {
requestAnimationFrame(render);
renderer.render(scene, camera);
};
render();
}
Apparently, it doesn't render anything on the screen. I used a Debugger, found out that everything has non zero values, no console errors, all THREE.JS scripts are loaded before this one, things are fine in the editor, but nothing on the screen. When, I change it to an simple procedural structure, it works. Is there a problem in my code or is there a JS concept I am missing in the implementation ?
Followed tutorials from here
http://threejs.org/docs/#Manual/Introduction/Creating_a_scene
http://blog.teamtreehouse.com/the-beginners-guide-to-three-js
Doesn't work on IE11, Chrome, Firefox!
you have passed incorrect argument to BoxGeometry. transformVector3 is Vector3 so you should write:
geometry = new THREE.BoxGeometry(transformVector3.scale.x,
transformVector3.scale.y,
transformVector3.scale.z );
position is not assigned to your mesh:
transform = transformVector3;
material = materialShader;
mesh = new THREE.Mesh(geometry, material);
//here
mesh.position.copy(transform.position);
Related
I'm trying to import blender scene to three.js with ObjectLoader() function. I want this to be as easy as possible, without animation just objects with right texture and colour in right place. Unfortunately three.js documentation is not a friendly place for newbies. So far I managed to draw every object from scene but every object is in different colour, plane lacks its texture and they are all in wrong places. What am I doing wrong? Here is my .js code:
var scene, camera, renderer;
var WIDTH = window.innerWidth;
var HEIGHT = window.innerHeight;
function init() {
scene = new THREE.Scene();
initCamera();
initLights();
initRenderer();
document.body.appendChild(renderer.domElement);
}
function initCamera() {
camera = new THREE.PerspectiveCamera(70, WIDTH / HEIGHT, 1, 10);
camera.position.set(0, 3.5, 5);
camera.lookAt(scene.position);
}
function initRenderer() {
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(WIDTH, HEIGHT);
}
function initLights() {
var light = new THREE.AmbientLight(0xffffff);
scene.add(light);
}
var loader = new THREE.ObjectLoader();
loader.load('./city.json', function(loadedObj) {
mesh = new THREE.Mesh(loadedObj);
var plane = loadedObj.getObjectByName("plane");
var building1 = loadedObj.getObjectByName("building1");
var building2 = loadedObj.getObjectByName("building2");
var building3 = loadedObj.getObjectByName("building3");
var building4 = loadedObj.getObjectByName("building4");
var building5 = loadedObj.getObjectByName("building5");
var building6 = loadedObj.getObjectByName("building6");
var building7 = loadedObj.getObjectByName("building7");
var building8 = loadedObj.getObjectByName("building8");
scene.add(loadedObj);
console.log(building1);
console.log(building2);
console.log(building3);
console.log(building4);
console.log(building5);
console.log(building6);
console.log(building7);
console.log(building8);
});
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
}
init();
render();
Is it possible that there is problem with way of exporting from blender not with code?
EDIT: Sorry about that, here's my city.json file
city.json
I'm using THREE.Plane to clip my STL model.
localPlane = new THREE.Plane( new THREE.Vector3( 0, -1, 0 ), 4);
.
.
.
material = new THREE.MeshPhongMaterial( {
color: 0xffffff,
side: THREE.DoubleSide,
clippingPlanes: [
localPlane,
],
clipShadows: true
} );
It's working; but the problem is that the whole object's top is clipped by this infinity sized plane. I want it to clip just a small part of it (It seems that there is no way to scale THREE.Plane)
I also tried using ThreeCSG.js but it seems inconvenient with STL objects!
Here is what I get:
Yes, the removal of the intersection of clipping planes is supported in three.js. You can use a pattern like this one:
// clipping planes
var localPlanes = [
new THREE.Plane( new THREE.Vector3( - 1, 0, 0 ), 1 ),
new THREE.Plane( new THREE.Vector3( 0, - 1, 0 ), 1 )
];
// material
var material = new THREE.MeshPhongMaterial( {
color: 0xffffff,
side: THREE.DoubleSide,
clippingPlanes: localPlanes,
clipIntersection: true
} );
Also, see the three.js example.
three.js r.85
Edit: Follow WestLangley's advice. I'll leave this her as an alternate though less efficient means of performing the clipping.
Clipping planes are infinite. There's no getting around that. So what can you do? Multiple clipping planes in multiple render passes!
To do this, you'll need to turn off auto-clearing, and do your own manual buffer clearing.
renderer = new THREE.WebGLRenderer();
renderer.autoClear = false;
Now let's say plane1 is the clipping plane you currently have.
material = new THREE.MeshPhongMaterial( {
...
clippingPlanes: [
plane1,
],
clipShadows: true
} );
var myMesh = new THREE.Mesh(geometry, material);
That clips the top half of myMesh when you call render. So you want to work with the remainder.
First, make another plane, plane2, be the inverse of plane1. plane2 will then clip the BOTTOM of myMesh. But if you render one pass using plane1, and another using plane2, then you're back with a full mesh. So you'll need a third clip plane, plane3, which clips only the desired half of myMesh. Putting plane2 and plane3 in the same render pass will result in only 1/4 of myMesh rendering.
var pass1ClipPlanes = [
plane1
],
pass2ClipLanes = [
plane2, // this plane is the inverse of plane 1, so it clips the opposite of plane1
plane3 // this clips the left/right half of the model
];
Then when you go to render, clear the draw buffers first, then call two render passes, updating the clip planes between them.
// clear the draw buffers
renderer.clear();
// clip the top
myMesh.material.clipPlanes = pass1ClipPlanes;
renderer.render(scene, camera);
// clip the bottom and one side
myMesh.material.clipPlanes = pass2ClipPlanes;
renderer.render(scene, camera);
The first pass renders the bottom of the model, and the second pass renders half of the top.
ETA: Example
var renderer, scene, camera, controls, stats;
var cube,
pass1ClipPlanes,
pass2ClipPlanes;
var WIDTH = window.innerWidth,
HEIGHT = window.innerHeight,
FOV = 35,
NEAR = 1,
FAR = 1000;
function init() {
document.body.style.backgroundColor = "slateGray";
renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
renderer.localClippingEnabled = true;
renderer.autoClear = false;
document.body.appendChild(renderer.domElement);
document.body.style.overflow = "hidden";
document.body.style.margin = "0";
document.body.style.padding = "0";
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(FOV, WIDTH / HEIGHT, NEAR, FAR);
camera.position.z = 50;
scene.add(camera);
controls = new THREE.TrackballControls(camera, renderer.domElement);
controls.dynamicDampingFactor = 0.5;
controls.rotateSpeed = 3;
var light = new THREE.PointLight(0xffffff, 1, Infinity);
camera.add(light);
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0';
document.body.appendChild(stats.domElement);
resize();
window.onresize = resize;
// POPULATE EXAMPLE
var plane1 = new THREE.Plane(new THREE.Vector3(0, -1, 0), 0),
plane2 = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0),
plane3 = new THREE.Plane(new THREE.Vector3(-1, 0, 0), 0);
pass1ClipPlanes = [plane1];
pass2ClipPlanes = [plane2, plane3];
var cubeGeo = new THREE.BoxBufferGeometry(10, 10, 10),
cubeMat = new THREE.MeshPhongMaterial({
color: "red",
side: THREE.DoubleSide
});
cube = new THREE.Mesh(cubeGeo, cubeMat);
scene.add(cube);
animate();
}
function resize() {
WIDTH = window.innerWidth;
HEIGHT = window.innerHeight;
if (renderer && camera && controls) {
renderer.setSize(WIDTH, HEIGHT);
camera.aspect = WIDTH / HEIGHT;
camera.updateProjectionMatrix();
controls.handleResize();
}
}
function render() {
renderer.clear();
cube.material.clippingPlanes = pass1ClipPlanes;
renderer.render(scene, camera);
cube.material.clippingPlanes = pass2ClipPlanes;
renderer.render(scene, camera);
}
function animate() {
requestAnimationFrame(animate);
render();
controls.update();
stats.update();
}
function threeReady() {
init();
}
(function() {
function addScript(url, callback) {
callback = callback || function() {};
var script = document.createElement("script");
script.addEventListener("load", callback);
script.setAttribute("src", url);
document.head.appendChild(script);
}
addScript("https://threejs.org/build/three.js", function() {
addScript("https://threejs.org/examples/js/controls/TrackballControls.js", function() {
addScript("https://threejs.org/examples/js/libs/stats.min.js", function() {
threeReady();
})
})
})
})();
I am trying to create a 3d star view, with a movable camera to traverse stars (js objects) using three.js. In searching for something to get me going/started, I found some code (below) and modified it to what seemed 'logically' correct. The code:
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 500);
camera.position.set(0, 0, 100);
camera.lookAt(new THREE.Vector3(0, 0, 0));
var scene = new THREE.Scene();
var geometry = new THREE.Geometry();
// Starlist contains 1600+ stars
for (var i=0;i<oldstarlist.length;i++)
{
// Convert RA/DEC to x,y,z coordinates
var s0 = new Star(oldstarlist[i]['starname'], oldstarlist[i]['constellation'], oldstarlist[i]['RA'], oldstarlist[i]['DEC'], oldstarlist[i]['lightyears']);
var star = new THREE.Vector3();
star.x = s0.coordinates.X;
star.y = s0.coordinates.Y;
star.z = s0.coordinates.Z;
console.log(star.x,star.y,star.z);
geometry.vertices.push( star );
}
var starsMaterial = new THREE.PointsMaterial( { color: 0x888888 } );
var starField = new THREE.Points( geometry, starsMaterial );
scene.add( starField );
renderer.render(scene, camera);
I presumed the 'Points' was correct, and I am still not sure where to place the camera. To be sure, I checked around for any examples and tutorials I could find but found nothing similar to what I am looking for.
A working example can be found on my test site area at this address:
http://theangelfallseries.com/stars/sp/test3js.html
Any help is appreciated.
Is there a way to see the light rays from a point light in a Three js scene. I have tried fog but it makes the whole objects in the scene the color of fog.
var width = $('#g_pre_emo').width();
var scene = new THREE.Scene();
scene.fog = new THREE.Fog(0xffff00, 0, 10);
var camera = new THREE.PerspectiveCamera(50, width / 500, 0.1, 1000);
var renderer = new THREE.WebGLRenderer({antialias: false});
renderer.setSize(width, 500);
$('#g_pre_emo').append(renderer.domElement);
var intensity = 2.5;
var distance = 5;
var decay = 2.0;
var light = new THREE.AmbientLight(0x404040); // soft white light
scene.add(light);
renderer.shadowMap.Enabled = true;
renderer.setClearColor(0xffffff, 1);
var happyGroup = new THREE.Object3D();
var sadGroup = new THREE.Object3D();
var angryGroup = new THREE.Object3D();
var relaxedGroup = new THREE.Object3D();
scene.add(happyGroup);
scene.add(sadGroup);
scene.add(angryGroup);
scene.add(relaxedGroup);
var c1 = 0xffff00;
var sphere = new THREE.SphereGeometry(0.25, 16, 8);
light1 = new THREE.PointLight(c1, intensity, distance, decay);
light1.add(new THREE.Mesh(sphere, new THREE.MeshBasicMaterial({color: c1})));
scene.add(light1);
happyGroup.position.set(-3, 3, 0);
sadGroup.position.set(3, 3, 0);
angryGroup.position.set(-3, -3, 0);
relaxedGroup.position.set(3, -3, 0);
var happyGeometry = new THREE.SphereGeometry(1, 50, 50);
var happyMaterial = new THREE.MeshNormalMaterial();
var happySphere = new THREE.Mesh(happyGeometry, happyMaterial);
scene.add(happySphere);
happyGroup.add(happySphere);
var sadGeometry = new THREE.SphereGeometry(1, 50, 50);
var sadMaterial = new THREE.MeshNormalMaterial();
var sadSphere = new THREE.Mesh(sadGeometry, sadMaterial);
scene.add(sadSphere);
sadGroup.add(sadSphere);
var angryGeometry = new THREE.SphereGeometry(1, 50, 50);
var angryMaterial = new THREE.MeshNormalMaterial();
var angrySphere = new THREE.Mesh(angryGeometry, angryMaterial);
scene.add(angrySphere);
angryGroup.add(angrySphere);
var relaxedGeometry = new THREE.SphereGeometry(1, 50, 50);
var relaxedMaterial = new THREE.MeshNormalMaterial();
var relaxedSphere = new THREE.Mesh(relaxedGeometry, relaxedMaterial);
scene.add(relaxedSphere);
relaxedGroup.add(relaxedSphere);
renderer.gammaInput = true;
renderer.gammaOutput = true;
camera.position.z = 15;
function render() {
renderer.render(scene, camera);
}
;
render();
animate();
function animate() {
requestAnimationFrame(animate);
}
If i run the above code the i cant see any fog in the scene
the fiddle for above code is
https://jsfiddle.net/bqv5ynbo/1/
Possibly, you can use VolumetricSpotlightMaterial from Jerome Etienne.
For me it worked well for Three.js r71, though I haven't tried it with later revisions.
Example of usage
'Light Rays' aren't an automatically occurring thing.
Typically, light rays are created using advanced pixel shaders (stencil/shadow projection over lit region / volumetric fog) or in simple cases by creating simple alpha-blended polygons with 'ray' textures applied.
A point light is simply a light that does not apply directional calculations during it's shading phase. Instead, only distance based calculations are made.
Good Luck!
I am working in a ruby on rails project with three.js. I installed the corresponding gem and it seems to work just fine. But somehow the javascript still throws the following Error:
Uncaught ReferenceError: THREE is not defined
on the Line:
renderer = new THREE.WebGLRenderer();
The weird thing is that my program seems to be working. My object gets displayed.
my javscript file looks like this:
// set size to the size of the containing box
var box = document.getElementById('player');
if(box){
var boxSize = box.clientWidth;
}
var a = 0.05;
// set some camera attributes
var VIEW_ANGLE = 45,
ASPECT = 1,
NEAR = 0.1,
FAR = 10000;
var camera, scene, renderer;
var $player;
var char, materialChar ;
init();
animate();
function init() {
renderer = new THREE.WebGLRenderer();
camera = new THREE.PerspectiveCamera( 75, 1, 0.1, 10000 );
camera.position.y = 10;
camera.position.z = 20;
scene = new THREE.Scene();
// get the DOM element to attach to
// - assume we've got jQuery to hand
$player = $('#player');
// attach the render-supplied DOM element
$player.append(renderer.domElement);
// create the character
initChar();
// create a point light
addLight();
scene.add(camera);
// draw!
renderer.setSize(boxSize, boxSize);
renderer.render(scene, camera);
renderer.shadowMap.enabled = true;
document.getElementById("player").addEventListener("click", zoom);
}
function addLight(){
var dirLight = new THREE.DirectionalLight(0xffffff, 1);
dirLight.position.set(100, 100, 50);
scene.add(dirLight);
var ambLight = new THREE.AmbientLight(0x404040);
scene.add(ambLight);
var bluePoint = new THREE.PointLight(0x0033ff, 3, 150);
bluePoint.position.set( 70, 5, 70 );
scene.add(bluePoint);
scene.add(new THREE.PointLightHelper(bluePoint, 3));
var greenPoint = new THREE.PointLight(0x33ff00, 1, 150);
greenPoint.position.set( -70, 5, 70 );
scene.add(greenPoint);
scene.add(new THREE.PointLightHelper(greenPoint, 3));
}
function initChar(){
var textureLoader = new THREE.TextureLoader();
var texture = textureLoader.load('<%= asset_path 'grey.jpg' %>');
materialChar = new THREE.MeshBasicMaterial({
map: texture
});
var loader = new THREE.JSONLoader();
loader.load('<%= asset_path 'standard-male-figure2.json' %>', function(geometry){
char = new THREE.Mesh( geometry, materialChar );
scene.add(char);
});
}
function animate(){
requestAnimationFrame( animate );
render();
}
function render(){
//char.rotation.y += 0.05;
renderer.render( scene, camera );
}
function zoom(){
camera.position.z = camera.position.z - 10;
}
I have similar problem in Rails 4.2. I think the default jquery / Ajax gem is missing the following component. I have it linked in my erb which solved the problem. It can also be configured to precompile by using asset pipeline if you choose to.
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r79/three.min.js"></script>