how to Smooth .obj in Three.js - three.js

Is there any way to smooth an .OBJ in three.js ? I already load the model but it looks faceted
I already use the shading: THREE.SmoothShading, in the material but doesn't affect it
var Loader = new THREE.OBJLoader();
Loader.load('models/stockcarchasisc.obj', function(carGeo, materials) {
// var material = new THREE.MeshFaceMaterial(materials);
var map = new THREE.TextureLoader().load( "models/st_tex.jpg" );
map.wrapS = map.wrapT = THREE.RepeatWrapping; // This set/place UV coordinates at 0 !
var material2 = new THREE.MeshStandardMaterial({
color: 0xa65e00,
side: THREE.DoubleSide,
map: map,
});
carGeo.traverse( function(child) {
if (child instanceof THREE.Mesh) {
// apply custom material
child.material = material2;
// enable casting shadows
child.castShadow = true;
child.receiveShadow = true;
}
});
carGeo.position.y = 25;
carGeo.scale.set(25, 25, 25);
var helper = new THREE.VertexNormalsHelper( carGeo, 5, 0x00ff00, 5 );
scene.add(carGeo);
scene.add(helper);
});

Related

ThreeJS - Bounding Box not set on object with material

I've tried to add Bounding Box to my object but it seems to work only for the testObj, he does not work for my others objects with texture.
var testObj = new THREE.Mesh(
new THREE.CylinderGeometry( 1 , 1 , 4 , 8 ),
new THREE.MeshLambertMaterial({ color: 0xff00ff })
);
scene.add(testObj );
staticCollideMesh.push(testObj );
// PADDLE1
loaderTexture.load('http://localhost:8000/WoodTexture.jpg', function (texture ) {
var material = new THREE.MeshLambertMaterial( {
map: texture
});
var geometry = new THREE.BoxGeometry(PADDLE_WIDTH, PADDLE_HEIGHT, PADDLE_DEPTH );
paddle1 = new THREE.Mesh( geometry, material);
paddle1.castShadow = true;
paddle1.receiveShadow = true;
paddle1.name = "paddle1";
scene.add( paddle1 );
staticCollideMesh.push(paddle1);
}, undefined, function ( err ) {
console.error( 'WoodTexture1.jpg : An error happened.' );
}
);
This is how I add BBox and BoxHelper :
let constructCollisionBoxes = function() {
staticCollideMesh.forEach( function( mesh ){
mesh.BBox = new THREE.Box3().setFromObject( mesh );
mesh.BBoxHelper = new THREE.BoxHelper( mesh , 0xff0000 );
scene.add( mesh.BBoxHelper );
});
}
I don't know why the loop just apply for my cylinder ... I need help to understand why this is not working.
EDIT: thanks to #prisoner849 I just added the function in the loader
scene.add(paddle1);
staticCollideMesh.push(paddle1);
constructionCollisionMesh();
In case of using loaders, keep in mind, that loading is asynchronous, so when you call constructCollisionBoxes(), your box, whose creation relies on the moment of finishing of loading of the texture, is not in the staticCollideMesh array yet.
To fix it, you can do it this way:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 1000);
camera.position.set(0, 0, 10);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
var light = new THREE.DirectionalLight(0xffffff, 1);
light.position.setScalar(1);
scene.add(light);
scene.add(new THREE.AmbientLight(0xffffff, 0.25));
var staticCollideMesh = [];
var PADDLE_WIDTH = 3,
PADDLE_HEIGHT = 3,
PADDLE_DEPTH = 2;
var testObj = new THREE.Mesh(
new THREE.CylinderGeometry(1, 1, 4, 8),
new THREE.MeshLambertMaterial({
color: 0xff00ff
})
);
scene.add(testObj);
staticCollideMesh.push(testObj);
var texture = new THREE.TextureLoader().load(`https://threejs.org/examples/textures/uv_grid_opengl.jpg`);
// PADDLE1
var material = new THREE.MeshLambertMaterial({
map: texture
});
var geometry = new THREE.BoxGeometry(PADDLE_WIDTH, PADDLE_HEIGHT, PADDLE_DEPTH);
paddle1 = new THREE.Mesh(geometry, material);
paddle1.castShadow = true;
paddle1.receiveShadow = true;
paddle1.name = "paddle1";
scene.add(paddle1);
staticCollideMesh.push(paddle1);
let constructCollisionBoxes = function() {
staticCollideMesh.forEach(function(mesh) {
mesh.BBox = new THREE.Box3().setFromObject(mesh);
mesh.BBoxHelper = new THREE.BoxHelper(mesh, 0xff0000);
scene.add(mesh.BBoxHelper);
});
}
constructCollisionBoxes();
renderer.setAnimationLoop(() => {
renderer.render(scene, camera);
});
body {
overflow: hidden;
margin: 0;
}
<script src="https://unpkg.com/three#0.115.0/build/three.min.js"></script>
<script src="https://unpkg.com/three#0.115.0/examples/js/controls/OrbitControls.js"></script>

Threejs & PhysiJs physics engine not updated when Mesh rotate

I am a beginner of Threejs.
I created a Box Mesh and a Sphere Mesh and applied physics using physiJs.
What I want to do is to hit the ball when the Box Mesh rotates and passing through the ball.
However, when the box mesh rotates, it passes without hitting the ball.
I think the box mesh loses physicality when it starts spinning.
function createBall () {
var ball = null;
var ballGeo = new THREE.SphereGeometry(1.5, 30, 30);
var ballMat = Physijs.createMaterial(
new THREE.MeshBasicMaterial({specular: 0x111111})
, 0.3, 0.1
);
ball = new Physijs.SphereMesh(
ballGeo,
ballMat,
5
);
ball.position.set(30, 10, 0);
scene.add(ball);
}
function createBox () {
var material = Physijs.createMaterial(
new THREE.MeshLambertMaterial(
{
color: 0x8041D9,
}), 5, 0.3);
var boxMesh = new THREE.BoxGeometry(5, 5, 25);
box = new Physijs.BoxMesh(
boxMesh,
material,
5
);
box.position.z = 20;
scene.add(box);
}
function createHeightMap() {
var initColor = new THREE.Color( 0x00ff00 );
initColor.setHSL( 0.25, 0.85, 0.5 );
var ground_material = Physijs.createMaterial(
new THREE.MeshPhongMaterial(
{ color: 0x47C83E}
),
.5,
.5
);
var ground_geometry = new THREE.PlaneGeometry(800, 800, 100, 100);
ground = new Physijs.HeightfieldMesh(
ground_geometry,
ground_material,
0, // 질량
100, // PlaneGeometry 의 분할 세그먼트랑 똑같은 값으로 줘야 한다.
100 // PlaneGeometry 의 분할 세그먼트랑 똑같은 값으로 줘야 한다.
);
ground.position.y = -10;
ground.rotation.x = Math.PI / -2;
ground.receiveShadow = true;
var meshes = [];
var controls = new function () {
this.startRotate = false;
this.addBall = function () {
createBall();
};
this.addBox = function () {
createBox();
};
this.clearMeshes = function () {
meshes.forEach(function (e) {
scene.remove(e);
});
meshes = [];
}
};
var gui = new dat.GUI();
gui.add(controls, 'addBall');
gui.add(controls, 'addBox');
gui.add(controls, 'clearMeshes');
gui.add(controls, 'startRotate').onChange(function (e) {
isStartRoate = e;
});
return ground;
}
render = function () {
stats.update();
if (isStartRoate === true) {
var rotateMatrix = new THREE.Matrix4();
rotateMatrix.identity();
rotateMatrix.makeRotationY(0.05);
box.applyMatrix(rotateMatrix);
}
requestAnimationFrame(render);
renderer.render(scene, camera);
var axes = new THREE.AxesHelper(30);
scene.add(axes);
scene.simulate(undefined, 2);
};
function initStats() {
var stats = new Stats();
stats.setMode(0); // 0: fps, 1: ms
// Align top-left
stats.domElement.style.position = 'absolute';
stats.domElement.style.left = '0px';
stats.domElement.style.top = '0px';
document.getElementById("Stats-output").appendChild(stats.domElement);
return stats;
}
window.onload = initScene;
below is codepen link
codepen
It seems like physicality not updated.
please give me any idea
When using Physijs, you should use setLinearVelocity() or setAngularVelocity() in order to update the position and rotation of your objects in a physical correct way. The updated codepen shows this approach:
https://codepen.io/anon/pen/YJmajN
Besides, the way you create AxesHelper in the render loop is no good approach. Create the helper once during the setup up of your scene.

THREE.js Image aspect ratio

I am having trouble figuring out how to set a PlaneGeometry to a good aspect ratio based on the image size.
var material = new THREE.MeshBasicMaterial({
map : THREE.ImageUtils.loadTexture('img/bunny.png')
});
var plane = new THREE.Mesh(new THREE.PlaneGeometry(20, 20*.75), material);
plane.position.set(0, 10, -60)
scene.add(plane);
What I've tried so far sort of works, but I realise I'm still setting a fixed width/height on the Plane.
I'd like the plane to set the size of the image, then I could scale it down.
var planeGeom = new THREE.PlaneGeometry(20, 20);
var imgSrc = "https://upload.wikimedia.org/wikipedia/commons/5/5f/BBB-Bunny.png"
var mesh;
var tex = new THREE.TextureLoader().load(imgSrc, (tex) => {
tex.needsUpdate = true;
mesh.scale.set(1.0, tex.image.height / tex.image.width, 1.0);
});
var material = new THREE.MeshLambertMaterial({
color: 0xffffff,
map: tex
});
mesh = new THREE.Mesh(planeGeom, material);
scene.add(mesh);
//Working snippet is below...
var renderer = new THREE.WebGLRenderer();
var w = 300;
var h = 200;
renderer.setSize(w, h);
document.body.appendChild(renderer.domElement);
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(
45, // Field of view
w / h, // Aspect ratio
0.1, // Near
10000 // Far
);
camera.position.set(15, 10, 15);
camera.lookAt(scene.position);
controls = new THREE.OrbitControls(camera, renderer.domElement);
var light = new THREE.PointLight(0xFFFFFF);
light.position.set(20, 20, 20);
scene.add(light);
var light1 = new THREE.AmbientLight(0x808080);
light1.position.set(20, 20, 20);
scene.add(light1);
var planeGeom = new THREE.PlaneGeometry(20, 20);
var imgSrc = "https://upload.wikimedia.org/wikipedia/commons/5/5f/BBB-Bunny.png"
var mesh;
var tex = new THREE.TextureLoader().load(imgSrc, (tex) => {
tex.needsUpdate = true;
mesh.scale.set(1.0, tex.image.height / tex.image.width, 1.0);
});
var material = new THREE.MeshLambertMaterial({
color: 0xffffff,
map: tex
});
mesh = new THREE.Mesh(planeGeom, material);
scene.add(mesh);
renderer.setClearColor(0xdddddd, 1);
(function animate() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
})();
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://cdn.rawgit.com/mrdoob/three.js/master/examples/js/controls/OrbitControls.js"></script>
The accepted answer works but has to use the callback to set the width since the loader is asynchronous. Nowadays one can also use the loadAsync method, which IMO makes the code more readable:
const getImageRatioPlane = async () => {
const texture = await new TextureLoader().loadAsync(imgSrc);
const material = new MeshBasicMaterial({ map: texture });
const geometry = new PlaneGeometry(texture.image.width, texture.image.height);
const plane = new Mesh(geometry, material);
}

Adding a different colour to each side of this obj

I've recreated a bag model for my application and exported it into ThreeJs as an .obj:
I've assigned a different colour to every face found in the models geometry like this:
var geometry = new THREE.Geometry().fromBufferGeometry( bagMesh.children[0].geometry );
for (var i = 0; i < geometry.faces.length; i ++ ) {
var face = geometry.faces[i];
// 7 & 8 = front side
// can we flip its normal?
if(i === 7 || i === 8) {
face.color.setHex( 0xff0000 );
} else {
face.color.setHex( Math.random() * 0xffffff );
}
}
geometry.translate( 0, -1, 0.75);
mesh = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial({ vertexColors: THREE.FaceColors, side: THREE.DoubleSide }) );
scene.add(mesh);
I've identified the faces of the front-side at indices 7 and 8 of the faces array and turned them red.
The problem is that this colour can be seen when I look inside of the bag too:
I realize that this is because I've set the object to THREE.DoubleSide but if I change it to THREE.FrontSide then the sides only partially visible.
So my question is how do I assign a different unique colour to each side (all 11 of them, counting the inside too) without that colour appearing on that sides respective opposite?
I'm trying to keep things simple here by only using colours as opposed to mapping images onto it, which is what I'll want to eventually get to.
Note - My previous model solved this problem by treating each side as a seperate mesh but this caused other issues like z-hiding and flickering problems.
Thanks
EDIT
#WestLangley I've setup a fiddle to demonstrate what you added in your comment. Assuming that I got it right it didn't have the desired affect:
(function onLoad() {
var canvasElement;
var width, height;
var scene, camera;
var renderer;
var controls;
var pivot;
var bagMesh;
var planeMesh;
const objLoader = new THREE.OBJLoader2();
const fileLoader = new THREE.FileLoader();
init();
function init() {
container = document.getElementById('container');
initScene();
addGridHelper();
addCamera();
addLighting();
addRenderer();
addOrbitControls();
loadPlaneObj();
// Logic
var update = function() {};
// Draw scene
var render = function() {
renderer.render(scene, camera);
};
// Run game logic (update, render, repeat)
var gameLoop = function() {
requestAnimationFrame(gameLoop);
update();
render();
};
gameLoop();
}
/**** Basic Scene Setup ****/
function initScene() {
scene = new THREE.Scene();
scene.background = new THREE.Color(0xd3d3d3);
var axis = new THREE.AxesHelper();
scene.add(axis);
}
function addCamera() {
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(3,3,3);
scene.add(camera);
}
function addGridHelper() {
var planeGeometry = new THREE.PlaneGeometry(2000, 2000);
planeGeometry.rotateX(-Math.PI / 2);
var planeMaterial = new THREE.ShadowMaterial({
opacity: 0.2
});
var plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.position.y = -200;
plane.receiveShadow = true;
scene.add(plane);
var helper = new THREE.GridHelper(2000, 100);
helper.material.opacity = 0.25;
helper.material.transparent = true;
scene.add(helper);
var axis = new THREE.AxesHelper();
scene.add(axis);
}
// *********** Lighting settings **********************
function addLighting() {
var light = new THREE.HemisphereLight(0xffffff, 0xffffff, 1);
scene.add(light);
}
// ************** Material settings **************
function setMaterial(materialName) {
// get the object from the scene
var bagMesh = scene.getObjectByName('bag');
var material;
if (!materialName) {
materialName = materials.material;
}
if (bagMesh) {
var colour = parseInt(materials.colour);
switch (materialName) {
case 'MeshBasicMaterial':
material = new THREE.MeshBasicMaterial({
color: colour
});
break;
case 'MeshDepthMaterial':
material = new THREE.MeshDepthMaterial();
break;
case 'MeshLambertMaterial':
material = new THREE.MeshLambertMaterial({
color: colour
});
break;
case 'MeshNormalMaterial':
material = new THREE.MeshNormalMaterial();
break;
case 'MeshPhongMaterial':
material = new THREE.MeshPhongMaterial({
color: colour
});
break;
case 'MeshPhysicalMaterial':
material = new THREE.MeshPhysicalMaterial({
color: colour
});
break;
case 'MeshStandardMaterial':
material = new THREE.MeshStandardMaterial({
color: colour
});
break;
case 'MeshToonMaterial':
material = new THREE.MeshToonMaterial({
color: colour
});
break;
}
bagMesh.children.forEach(function(c) {
c.material = material;
});
}
}
function setMaterialColour(colour) {
materials.colour = colour;
setMaterial(null);
}
// ************** End of materials ***************
function addRenderer() {
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
container.appendChild(renderer.domElement);
}
function addOrbitControls() {
var controls = new THREE.OrbitControls(camera, renderer.domElement);
}
function addPivot() {
var cubeGeo = new THREE.BoxBufferGeometry(5, 5, 5);
var cubeMat = new THREE.MeshBasicMaterial();
pivot = new THREE.Mesh(cubeGeo, cubeMat);
bagMesh.position.x -= 15;
bagMesh.position.z -= 55;
pivot.add(bagMesh);
pivot.add(handle);
scene.add(pivot);
}
function loadPlaneObj() {
loadObj('Plane', 'https://rawgit.com/Katana24/threejs-experimentation/master/models/Plane.obj', 'https://rawgit.com/Katana24/threejs-experimentation/master/models/Plane.mtl', addPlaneToSceneSOAnswer);
}
function loadObj(objName, objUrl, mtlUrl, onLoadFunc) {
var onLoadMtl = function(materials) {
objLoader.setModelName(objName);
objLoader.setMaterials(materials);
fileLoader.setPath('');
fileLoader.setResponseType('arraybuffer');
fileLoader.load(objUrl,
function(onLoadContent) {
var mesh = objLoader.parse(onLoadContent);
onLoadFunc(mesh);
},
function(inProgress) {},
function(error) {
throw new Error('Couldnt load the model: ', error);
});
};
objLoader.loadMtl(mtlUrl, objName+'.mtl', onLoadMtl);
}
function addPlaneToSceneSOAnswer(mesh) {
var frontMaterial = new THREE.MeshBasicMaterial( { color : 0xff0000, side: THREE.FrontSide } );
var backMaterial = new THREE.MeshBasicMaterial( { color : 0x00ff00, side: THREE.BackSide } );
var geometry = new THREE.Geometry().fromBufferGeometry( mesh.children[0].geometry );
var length = geometry.faces.length;
geometry.faces.splice(14, 1);
for (var i = 0; i < geometry.faces.length; i ++ ) {
var face = geometry.faces[i];
face.color.setHex(Math.random() * 0xffffff);
}
mesh = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial({ vertexColors: THREE.FaceColors, side: THREE.DoubleSide }) );
mesh.material.side = THREE.FrontSide;
var mesh2 = new THREE.Mesh( geometry, mesh.material.clone() );
mesh2.material.side = THREE.BackSide;
// mesh2.material.vertexColors = THREE.NoColors;
mesh2.material.vertexColors = [new THREE.Color(0xff0000), new THREE.Color(0x00ff00), new THREE.Color(0x0000ff)];
mesh.add( mesh2 );
scene.add(mesh);
}
})();
body {
background: transparent;
padding: 0;
margin: 0;
font-family: sans-serif;
}
#canvas {
margin: 10px auto;
width: 800px;
height: 350px;
margin-top: -44px;
}
<body>
<div id="container"></div>
<script src="https://threejs.org/build/three.js"></script>
<script src="https://threejs.org/examples/js/libs/dat.gui.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script src="https://threejs.org/examples/js/loaders/MTLLoader.js"></script>
<script src="https://rawgit.com/mrdoob/three.js/dev/examples/js/loaders/LoaderSupport.js"></script>
<script src="https://rawgit.com/mrdoob/three.js/dev/examples/js/loaders/OBJLoader2.js"></script>
</body>
What am I missing here?
I followed along with Don's suggestion about the different materials but didn't know entirely what he meant.
I examined this question which details setting the materialIndex. I investigated what this means and what it means is that when you pass a geometry and an array of materials to a mesh like this:
mesh = new THREE.Mesh( geometry, [frontMaterial, backMaterial, otherMaterial] );
then that face will get the material (frontMaterial because it's at position 0) assigned to it.
Coming back to my original question, I decided to simplify (for the moment) and see if I could apply what I want to just a Plane mesh exported from Blender.
The Plane has two Faces when added into 3JS. I found I could flip each face or assign a different material to each but I needed to duplicate the faces in order to achieve this:
function addMeshTwoToScene() {
var frontMaterial = new THREE.MeshBasicMaterial( { color : 0xff0000, side: THREE.FrontSide } );
var backMaterial = new THREE.MeshBasicMaterial( { color : 0x00ff00, side: THREE.BackSide } );
var geometry = new THREE.Geometry().fromBufferGeometry( planeMesh.children[0].geometry );
// Duplicates the face
var length = geometry.faces.length;
for (var i = 0; i < length; i++ ) {
var face = geometry.faces[i];
var newFace = Object.assign({}, face);
geometry.faces.push(newFace);
}
for (var i = 0; i < geometry.faces.length; i ++ ) {
var face = geometry.faces[i];
if(i === 0 || i === 3) {
face.materialIndex = 0;
} else {
face.materialIndex = 1;
}
}
var mesh = new THREE.Mesh( geometry, [frontMaterial, backMaterial] );
scene.add(mesh);
}
This results in the following:
I'm not going to mark this as the accepted answer yet as I still need to apply it to the more complex model in the question plus I think there could still be a better way to do this, like flipping a particular vertex to some other value.
One solution would be to use a ShaderMaterial and define the colors based on whether the face is front or back facing.
Let me walk you through this simple example
Hold left click to rotate the mesh. If you're not familiar with ShaderFrog, click "Edit Source" on the right and scroll down the bottom of the fragment shader.
if (!gl_FrontFacing) gl_FragColor = vec4(vec3(0.0, 0.0, 1.0) * brightness, 1.0);
gl_FrontFacing is a boolean. Quite self explanatory, it'll return true if a face is front, and false otherwise.
The line reads "if the face is not front facing, render it blue at with alpha = 1.0.
Hoping that helps.

Three.js controlling shadows

I'm having trouble controlling shadows in THREE.js. First off, the shadow in my scene is way too dark. From what I've read, there was a shadowDarkness property, that is know longer available in the current version of three.js. Does anyone know a work around?
Also, in the attached image: the "backface" geometry is not occluding light on the shadow of the seat - however, you can see the backface of the stool in the reflection of the sphere(cubeCamera). Does anyone know how to fix that?
On a side note: chrome gives me an error "Uncaught TypeError: Cannot set property 'visible' of undefined," regarding the
frameMesh.visible = false;
cubeCameraFrame.position.copy(frameMesh.position);
cubeCameraFrame.updateCubeMap(renderer, scene);
frameMesh.visible = true;
part of my code. Could that be effecting the shadows in some way? I can comment that part of the code and it will have little effect on the stoolframes "reflective" appearance. However it then no longer is reflects in the sphere. Any help is much appreciated.
///webGL - Locking down the Basics
/////////////////////////////////////////////////////////////Environment Settings///////////////////////////////////////////////////////////////////////
///Renderer
var scene = new THREE.Scene();
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMapType = THREE.PCFSoftShadowMap;
renderer.shadowMapEnabled = true;
document.body.appendChild(renderer.domElement);
///Camera's
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
scene.add(camera);
camera.position.set(0, 16, 25);
camera.rotation.x += -0.32;
var cubeCameraSphere = new THREE.CubeCamera(1, 1000, 256); // parameters: near, far, resolution
cubeCameraSphere.renderTarget.texture.minFilter = THREE.LinearMipMapLinearFilter; // mipmap filter
scene.add(cubeCameraSphere);
var cubeCameraFrame = new THREE.CubeCamera(1, 1000, 256); // parameters: near, far, resolution
cubeCameraFrame.renderTarget.texture.minFilter = THREE.LinearMipMapLinearFilter; // mipmap filter
scene.add(cubeCameraFrame);
///Controls
///Lights
var lightSpot_Right = new THREE.SpotLight(0xffffff);
lightSpot_Right.position.set(50, 50, 0);
lightSpot_Right.intensity = 1.25;
lightSpot_Right.castShadow = true;
lightSpot_Right.shadowDarkness = 0.1;
lightSpot_Right.shadowMapWidth = 2048;
lightSpot_Right.shadowMapHeight = 2048;
lightSpot_Right.shadowCameraNear = 1;
lightSpot_Right.shadowCameraFar = 100;
lightSpot_Right.shadowCameraFov = 65;
scene.add(lightSpot_Right);
var lightDirect_Left = new THREE.DirectionalLight(0xffffff, 0.25);
lightDirect_Left.position.set(-1, 0, 0);
scene.add(lightDirect_Left);
///Loaders
var loadTexture = new THREE.TextureLoader();
var loader = new THREE.JSONLoader();
///skyBox
var imagePrefix = "textures/";
var directions = ["skyboxRight", "skyboxLeft", "skyboxTop", "skyboxBottom", "skyboxFront", "skyboxBack"];
var imageSuffix = ".jpg";
var skyMaterialArray = [];
for (var i = 0; i < 6; i++)
skyMaterialArray.push(new THREE.MeshBasicMaterial({
map: new THREE.TextureLoader().load(imagePrefix + directions[i] + imageSuffix),
side: THREE.BackSide
}));
var skyMaterial = new THREE.MeshFaceMaterial(skyMaterialArray);
var skyGeometry = new THREE.CubeGeometry(1000, 1000, 1000);
var skyBox = new THREE.Mesh(skyGeometry, skyMaterial);
scene.add(skyBox);
////////////////////////////////////////////////////////Object Settings//////////////////////////////////////////////////////////////////
//Textures
var seatTexture = loadTexture.load("textures/Maharam_Mister_Notice_Diffuse.jpg");
seatTexture.wrapS = THREE.RepeatWrapping;
seatTexture.wrapT = THREE.RepeatWrapping;
seatTexture.repeat.set(3, 3);
var conceteDiffuse = loadTexture.load("textures/Contrete_Diffuse.jpg");
conceteDiffuse.wrapS = THREE.RepeatWrapping;
conceteDiffuse.wrapT = THREE.RepeatWrapping;
conceteDiffuse.repeat.set(3, 3);
var conceteNormal = loadTexture.load("textures/Contrete_Normal.jpg");
conceteNormal.wrapS = THREE.RepeatWrapping;
conceteNormal.wrapT = THREE.RepeatWrapping;
conceteNormal.repeat.set(3, 3);
var conceteSpecular = loadTexture.load("textures/Contrete_Specular.jpg");
conceteSpecular.wrapS = THREE.RepeatWrapping;
conceteSpecular.wrapT = THREE.RepeatWrapping;
conceteSpecular.repeat.set(3, 3);
///Materials
var seatMaterial = new THREE.MeshLambertMaterial({
map: seatTexture,
side: THREE.DoubleSide
});
var frameMaterial = new THREE.MeshPhongMaterial({
envMap: cubeCameraFrame.renderTarget,
color: 0xcccccc,
emissive: 0x404040,
shininess: 10,
reflectivity: .8
});
var frameHardwareMat = new THREE.MeshPhongMaterial({
color: 0x000000
});
var feetMat = new THREE.MeshPhongMaterial({
color: 0x050505,
shininess: 99
});
var sphereMat = new THREE.MeshPhongMaterial({
envMap: cubeCameraSphere.renderTarget
});
var groundMat = new THREE.MeshPhongMaterial({
map: conceteDiffuse,
specularMap: conceteSpecular,
normalMap: conceteNormal,
normalScale: new THREE.Vector2( 0.0, 0.6 ),
shininess: 50
});
///Geometry and Meshes
var barStool = new THREE.Object3D();
scene.add(barStool);
var seatMesh;
loader.load("models/stoolSeat.js", function (geometry, material) {
seatMesh = new THREE.Mesh(geometry, seatMaterial);
seatMesh.scale.set(.5, .5, .5);
seatMesh.castShadow = true;
seatMesh.receiveShadow = true;
barStool.add(seatMesh);
});
var frameMesh;
loader.load("models/stoolFrame.js", function (geometry, material) {
frameMesh = new THREE.Mesh(geometry, frameMaterial);
frameMesh.scale.set(.5, .5, .5);
frameMesh.castShadow = true;
barStool.add(frameMesh);
});
var frameFeetMesh;
loader.load("models/stoolFeet.js", function (geometry, material) {
frameFeetMesh = new THREE.Mesh(geometry, feetMat);
frameFeetMesh.scale.set(.5, .5, .5);
frameFeetMesh.castShadow = true;
barStool.add(frameFeetMesh);
});
var frameHardwareMesh;
loader.load("models/stoolHardware.js", function (geomtry, material) {
frameHardwareMesh = new THREE.Mesh(geomtry, frameHardwareMat);
frameHardwareMesh.scale.set(.5, .5, .5);
barStool.add(frameHardwareMesh);
});
var sphereGeo = new THREE.SphereGeometry(2.5, 50, 50);
var sphereMesh = new THREE.Mesh(sphereGeo, sphereMat);
scene.add(sphereMesh);
sphereMesh.position.set(-10, 5, 0);
var groundGeo = new THREE.PlaneGeometry(100, 50, 1);
var groundMesh = new THREE.Mesh(groundGeo, groundMat);
scene.add(groundMesh);
groundMesh.rotation.x = -90 * Math.PI / 180;
groundMesh.receiveShadow = true;
///Render Scene
var render = function () {
requestAnimationFrame(render);
barStool.rotation.y += 0.01;
skyBox.rotation.y -= 0.0002;
sphereMesh.visible = false;
cubeCameraSphere.position.copy(sphereMesh.position);
cubeCameraSphere.updateCubeMap(renderer, scene);
sphereMesh.visible = true;
//frameMesh.visible = false;
//cubeCameraFrame.position.copy(frameMesh.position);
//cubeCameraFrame.updateCubeMap(renderer, scene);
//frameMesh.visible = true;
renderer.render(scene, camera);
};
render();
Shadow darkness has been removed. The best work-around is to add ambient light to your scene.
scene.add( new THREE.AmbientLight( 0xffffff, 0.3 );
You may want to concurrently reduce the intensity of your SpotLight.
The shadow is actually correct given only back faces are casting shadows. It appears that the stool is hollow under the seat -- in other words, the seat is not a closed volume. Add a bottom to the underside of your seat.
Alternatively, you can leave your model as-is and experiment with
renderer.shadowMap.cullFace = THREE.CullFaceNone;
Finally, you are getting the error because you are accessing frameMesh in the animation loop before it is defined in the loader callback. The callback is asynchronous.
if ( frameMesh !== undefined ) {
// your code
}
three.js r.75

Resources