I want a bloom effect for my scene when using an emissive map like shown in this ThreeJS Example.
I've tried to understand the code a little bit but I'm basically stuck. The examples are all made with NPM and I do not use this method for my project. I'm sure it is possible to have the bloom effect without the help of this but I struggle to make sense of it all.
As for what I have already, just a basic setup with StandarMeshMaterial:
scene = new THREE.Scene();
loader = new THREE.TextureLoader()
camera = new THREE.PerspectiveCamera( 47, (window.innerWidth/window.innerHeight) / (windowHeight*heightRatio), 0.01, 10000 );
renderer = new THREE.WebGLRenderer( { canvas: document.getElementById( canvasElement ), antialias: true, alpha: true } );
controls = new THREE.OrbitControls( camera, renderer.domElement );
ect..
function animate() {
requestAnimationFrame( animate );
controls.update();
renderer.render( scene, camera );
};
ect..
I really just want to apply some post-processing effect so my emissive materials actually appear to be glowing, which is not whats happening at the moment but I just cannot figure out how..
What would be the simplest way to get this result?
The examples are not made with npm.
Here's the example running below. The only thing changed is the paths of the modules and the url of the model.
#info > * {
max-width: 650px;
margin-left: auto;
margin-right: auto;
}
<link type="text/css" rel="stylesheet" href="https://threejs.org/examples/main.css">
<div id="container"></div>
<div id="info">
three.js - Bloom pass by Prashant Sharma and Ben Houston
<br/>
Model: Primary Ion Drive by
Mike Murdock, CC Attribution.
</div>
<script type="module">
import * as THREE from 'https://threejs.org/build/three.module.js';
import Stats from 'https://threejs.org/examples/jsm/libs/stats.module.js';
import { GUI } from 'https://threejs.org/examples/jsm/libs/dat.gui.module.js';
import { OrbitControls } from 'https://threejs.org/examples/jsm/controls/OrbitControls.js';
import { GLTFLoader } from 'https://threejs.org/examples/jsm/loaders/GLTFLoader.js';
import { EffectComposer } from 'https://threejs.org/examples/jsm/postprocessing/EffectComposer.js';
import { RenderPass } from 'https://threejs.org/examples/jsm/postprocessing/RenderPass.js';
import { UnrealBloomPass } from 'https://threejs.org/examples/jsm/postprocessing/UnrealBloomPass.js';
let camera, stats;
let composer, renderer, mixer, clock;
const params = {
exposure: 1,
bloomStrength: 1.5,
bloomThreshold: 0,
bloomRadius: 0
};
init();
function init() {
const container = document.getElementById( 'container' );
stats = new Stats();
container.appendChild( stats.dom );
clock = new THREE.Clock();
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.toneMapping = THREE.ReinhardToneMapping;
container.appendChild( renderer.domElement );
const scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 100 );
camera.position.set( - 5, 2.5, - 3.5 );
scene.add( camera );
const controls = new OrbitControls( camera, renderer.domElement );
controls.maxPolarAngle = Math.PI * 0.5;
controls.minDistance = 1;
controls.maxDistance = 10;
scene.add( new THREE.AmbientLight( 0x404040 ) );
const pointLight = new THREE.PointLight( 0xffffff, 1 );
camera.add( pointLight );
const renderScene = new RenderPass( scene, camera );
const bloomPass = new UnrealBloomPass( new THREE.Vector2( window.innerWidth, window.innerHeight ), 1.5, 0.4, 0.85 );
bloomPass.threshold = params.bloomThreshold;
bloomPass.strength = params.bloomStrength;
bloomPass.radius = params.bloomRadius;
composer = new EffectComposer( renderer );
composer.addPass( renderScene );
composer.addPass( bloomPass );
new GLTFLoader().load( 'https://threejs.org/examples/models/gltf/PrimaryIonDrive.glb', function ( gltf ) {
const model = gltf.scene;
scene.add( model );
mixer = new THREE.AnimationMixer( model );
const clip = gltf.animations[ 0 ];
mixer.clipAction( clip.optimize() ).play();
animate();
} );
const gui = new GUI();
gui.add( params, 'exposure', 0.1, 2 ).onChange( function ( value ) {
renderer.toneMappingExposure = Math.pow( value, 4.0 );
} );
gui.add( params, 'bloomThreshold', 0.0, 1.0 ).onChange( function ( value ) {
bloomPass.threshold = Number( value );
} );
gui.add( params, 'bloomStrength', 0.0, 3.0 ).onChange( function ( value ) {
bloomPass.strength = Number( value );
} );
gui.add( params, 'bloomRadius', 0.0, 1.0 ).step( 0.01 ).onChange( function ( value ) {
bloomPass.radius = Number( value );
} );
window.addEventListener( 'resize', onWindowResize );
}
function onWindowResize() {
const width = window.innerWidth;
const height = window.innerHeight;
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.setSize( width, height );
composer.setSize( width, height );
}
function animate() {
requestAnimationFrame( animate );
const delta = clock.getDelta();
mixer.update( delta );
stats.update();
composer.render();
}
</script>
What you need to do is use <script type="module"> so that modern import statements work
You should then copy the three.js files as tree like this
someFolder
|
├-build
| |
| +-three.module.js
|
+-examples
|
+-jsm
|
+-controls
| |
| +-OrbitControls.js
| +-TrackballControls.js
| +-...
|
+-loaders
| |
| +-GLTFLoader.js
| +-...
|
...
And adjust your paths as appropriate
See this article
First, NPM is not a framework. It is a package manager to install libraries your project depends on without manually downloading and copying the scripts to your project folder. What I read from your question is that you are not familiar with that module approach. You want to insert scripts and all three.js related stuff should be available under the global namespace THREE?
Assuming that you downloaded three.js to a folder named three, you could import the scripts as follows. Ensure to load the scripts from examples/js and not examples/jsm.
<script src="three/build/three.min.js"></script>
<script src="three/examples/js/controls/OrbitControls.js"></script>
<script src="three/examples/js/loaders/GLTFLoader.js"></script>
<script src="three/examples/js/postprocessing/EffectComposer.js"></script>
<script src="three/examples/js/postprocessing/RenderPass.js"></script>
<script src="three/examples/js/postprocessing/UnrealBloomPass.js"></script>
Now, you can use these classes under the THREE namespace.
const renderScene = new THREE.RenderPass( scene, camera );
const bloomPass = new THREE.UnrealBloomPass( new THREE.Vector2( window.innerWidth, window.innerHeight ), 1.5, 0.4, 0.85 );
Follow the example code, remove the import statements and add THREE where missing.
first, i have already read this question didn't help
How i do: first i export a model from C4D to .ojb. Then i import the obj into www.trheejs/editor
I fill all the blank
then from the tree i select my object and export it to a Threejs Object, it save a .json file
My code
<script>
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 kiss = new THREE.Object3D(), loader = new THREE.JSONLoader(true);
loader.load( "brikk2.json", function ( geometry, materials ) {
var mesh = new THREE.Mesh( geometry, new THREE.MeshPhongMaterial( { color: 0xff0000, ambient: 0xff0000 } ) );
scene.add( mesh );
});
var render = function () {
requestAnimationFrame(render);
renderer.render(scene, camera);
};
render();
</script>
When i run i have theses error messages
THREE.WebGLRenderer 67 three.js:20806
THREE.WebGLRenderer: elementindex as unsigned integer not supported. three.js:26942
XHR finished loading: "http://xxxxxx.xx/tst/mrdoob-three2/brikk2.json". three.js:12018
THREE.JSONLoader.loadAjaxJSON three.js:12018
THREE.JSONLoader.load three.js:11942
load test.html:23
(anonymous function) test.html:28
Uncaught TypeError: Cannot read property 'length' of undefined three.js:12087
parseModel three.js:12087
THREE.JSONLoader.parse three.js:12028
xhr.onreadystatechange three.js:11969
the Json i load
{
"metadata": {
"version": 4.3,
"type": "Object",
"generator": "ObjectExporter"
},
"geometries": [
{
"uuid": "213E28EF-E388-46FE-AED3-54695667E086",
"name": "brikkG",
"type": "Geometry",
"data": {
"vertices": [0.036304,-0.016031,-0.027174,0.036304,0.......
........ 232,1228,1139,1141,1140,1]
}
}],
"materials": [
{
"uuid": "F74C77E4-8371-41BC-85CA-31FC96916CC6",
"name": "lego",
"type": "MeshPhongMaterial",
"color": 16721408,
"ambient": 16777215,
"emissive": 0,
"specular": 16777215,
"shininess": 30,
"opacity": 1,
"transparent": false,
"wireframe": false
}],
"object": {
"uuid": "3BAAB8CA-1EB7-464A-8C6D-FC4BBB3C63C6",
"name": "BrikkM",
"type": "Mesh",
"geometry": "213E28EF-E388-46FE-AED3-54695667E086",
"material": "F74C77E4-8371-41BC-85CA-31FC96916CC6",
"matrix": [1000,0,0,0,0,1000,0,0,0,0,1000,0,0,0,0,1]
}
}
structure of the json file
basically i have tried all i have read about importing native json into ThreeJS, i tried files from the treejs/editor or clara.io still have the same error message, i have no idea anymore, i spend 3 days trying all the way i read to solve this.
If i try to create geometry like CubeGeometry it render without problems, but at soon as i try with native json, nothing work anymore
somebody could help ?
Ok, i found the answer here: http://helloenjoy.com/2013/from-unity-to-three-js/
the native json code is perfect, it's just no be mean to be loaded with JSONLoader but with ObjectLoader (do not mismatch with OBJLoader like i did i one of my experiment). JSONLoader is mean to load json, but with a different format/structure. ObjectLoader is mean to load native format that is also written in json but with a native structure/format.
so use
var loader = new THREE.ObjectLoader();
loader.load( 'brikk2.json', function ( object ) {
scene.add( object );
} );
and it's working
full example code
<body>
<script src="build/three.min.js"></script>
<script>
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
var renderer = new THREE.WebGLRenderer();
renderer.setClearColor( 0xffffff, 1);
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var ambient = new THREE.AmbientLight( 0x101030 );
scene.add( ambient );
var directionalLight = new THREE.DirectionalLight( 0xffeedd );
directionalLight.position.set( 0, 0, 1 );
scene.add( directionalLight );
var loader = new THREE.ObjectLoader();
loader.load( 'brikk2.js', function ( object ) {
scene.add( object );
} );
camera.position.z = 5;
var render = function () {
requestAnimationFrame(render);
renderer.render(scene, camera);
};
render();
</script>
</body>
EDIT
The top code i showed in the top question was right but it was for Geometry loading
loader = new THREE.JSONLoader();
loader.load( 'ugeometry.json', function ( geometry ) {
mesh = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( { envMap: THREE.ImageUtils.loadTexture( 'environment.jpg', new THREE.SphericalReflectionMapping() ), overdraw: 0.5 } ) );
scene.add( mesh );
So the recap.
if from threes/editor or Clara.io you save GEOMETRY use JSONLoader, if you save as OBJECT use ObjectLoader, and if you save as SCENE they should be a SceneLoader (unverified)
I have in this fiddle an example of the problem I'm having: http://jsfiddle.net/saward/78Bjk/7/
If you uncomment scene.add(tree_mesh) and scene.add(mesh2), and comment out scene.add(mesh) then you can see both objects. But when I merge both, the material information for tree_mesh seems to be lost. If I modify the mesh to use the same material as mesh2, then both objects display but obviously with the wrong material.
I would appreciate help in understanding what's going on here and how to fix it!
Thanks
Here is the code from the fiddle (requires three.js r57):
var camera, scene, renderer, geometry, material, mesh1, mesh2, mesh;
init();
animate();
function init() {
var tree = {
"metadata" :
{
"formatVersion" : 3.1,
"sourceFile" : "tree.obj",
"generatedBy" : "OBJConverter",
"vertices" : 24,
"faces" : 18,
"normals" : 0,
"colors" : 0,
"uvs" : 0,
"materials" : 1
},
"scale" : 1.000000,
"materials": [ {
"DbgColor" : 15658734,
"DbgIndex" : 0,
"DbgName" : "Material",
"colorAmbient" : [0.0, 0.0, 0.0],
"colorDiffuse" : [0.64, 0.64, 0.64],
"colorSpecular" : [0.5, 0.5, 0.5],
"illumination" : 2,
"opticalDensity" : 1.0,
"specularCoef" : 96.078431,
"transparency" : 1.0
}],
"vertices": [1.000000,-1.000000,-1.000000,1.000000,-1.000000,1.000000,-1.000000,-1.000000,1.000000,-1.000000,-1.000000,-1.000000,0.590806,-0.802478,-0.590806,0.590806,-0.802478,0.590807,-0.590806,-0.802478,0.590806,-0.590806,-0.802478,-0.590806,0.406036,0.737103,-0.406036,0.406036,0.737103,0.406036,-0.406036,0.737103,0.406036,-0.406036,0.737103,-0.406036,0.406036,-0.810673,-0.406036,0.406036,-0.810673,0.406036,-0.406036,-0.810673,0.406036,-0.406036,-0.810673,-0.406036,-0.703524,0.091037,0.703524,-0.703524,0.091037,-0.703524,0.703524,0.091037,-0.703524,0.703524,0.091037,0.703524,-0.703524,1.498086,0.703524,-0.703524,1.498086,-0.703524,0.703524,1.498086,-0.703524,0.703524,1.498086,0.703524],
"morphTargets": [],
"morphColors": [],
"normals": [],
"colors": [],
"uvs": [[]],
"faces": [3,0,1,2,3,0,3,4,7,6,5,0,3,0,4,5,1,0,3,1,5,6,2,0,3,2,6,7,3,0,3,4,0,3,7,0,3,12,8,9,13,0,3,13,9,10,14,0,3,14,10,11,15,0,3,15,11,8,12,0,3,8,9,10,11,0,3,15,14,13,12,0,3,20,21,17,16,0,3,21,22,18,17,0,3,22,23,19,18,0,3,23,20,16,19,0,3,16,17,18,19,0,3,23,22,21,20,0]
};
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.z = 500;
scene.add(camera);
geometry = new THREE.CubeGeometry(200, 200, 200);
material = new THREE.MeshNormalMaterial();
var loader = new THREE.JSONLoader();
var tree_obj = loader.parse(tree, null);
var tree_materials = tree_obj.materials;
var tree_face_materials = new THREE.MeshFaceMaterial(tree_materials);
var tree_geo = tree_obj.geometry;
var tree_mesh = new THREE.Mesh(tree_geo, tree_face_materials);
tree_mesh.scale.x = tree_mesh.scale.y = tree_mesh.scale.z = 100;
mesh2 = new THREE.Mesh(geometry, material);
mesh2.position.y = 200;
console.log(tree_mesh.scale);
//scene.add(tree_mesh);
//scene.add(mesh2);
materials = [];
THREE.GeometryUtils.setMaterialIndex(tree_mesh.geometry, 0);
THREE.GeometryUtils.setMaterialIndex(mesh2.geometry, 1);
materials.push(tree_face_materials);
materials.push(material);
var new_geo = new THREE.Geometry();
THREE.GeometryUtils.merge(new_geo, tree_mesh);
THREE.GeometryUtils.merge(new_geo, mesh2);
mesh = new THREE.Mesh(new_geo, new THREE.MeshFaceMaterial(materials));
scene.add(mesh);
renderer = new THREE.CanvasRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
}
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
mesh.rotation.x += 0.01;
mesh.rotation.y += 0.02;
renderer.render(scene, camera);
}
Update: The way I specifically solved this was by using the current dev version of three.js 58, to add the materials for each model to a larger array.
As noted by the accepted answer, you can't use MeshFaceMaterial as a material, so iterate over all the materials within the MeshFaceMaterial, adding them in order.
Then note the index of the first material in the larger array for each model. Then when it comes time to merge the meshes, instead of using setMaterialIndex, give it the index of the first material in the array for that specific model. Along these lines:
THREE.GeometryUtils.merge(large_geo, some_mesh, some_mesh.material_offset);
large_mesh = new THREE.Mesh(large_geo, new THREE.MeshFaceMaterial(materials_list));
Where "some_mesh.material_offset" will be a new value you set and store for yourself somewhere. This will not work with r57 or lower.
When using MeshFaceMaterial( materials ), then materials must be an array of materials. You can't include MeshFaceMaterial as one of the materials.
In your case, it would be:
materials = [];
materials.push( tree_obj.materials[0] );
materials.push( material );
mesh = new THREE.Mesh( new_geo, new THREE.MeshFaceMaterial( materials ) );
Fiddle: http://jsfiddle.net/78Bjk/8/
three.js r.57
My model loads fine with this code:
loader.load( "js/charWalk01.js", function( geometry, materials ) {
mesh = new THREE.Mesh( geometry, new THREE.MeshLambertMaterial() );
scene.add( mesh );
} );
However, when I try to use the MeshFaceMaterial (so as to use the material in the JSON file), I get two really odd three.min.js error messages (below).
loader.load( "js/charWalk01.js", function( geometry, materials ) {
materials[ 0 ].morphTargets = true;
mesh = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial() );
scene.add( mesh );
} );
The errors are:
TypeError: 'undefined' is not an object (evaluating 'a.map') three.min.js:347
TypeError: 'undefined' is not an object (evaluating 'ma.attributes') three.min.js:429
The JSON file is perfectly normal (created with the OBJ converter), here's the material code from it:
"materials": [ {
"DbgColor" : 15658734,
"DbgIndex" : 0,
"DbgName" : "Mat.1",
"colorDiffuse" : [1.0, 1.0, 1.0],
"colorSpecular" : [0.4, 0.52, 0.53],
"illumination" : 4,
"mapDiffuse" : "Character_01.jpg"
}],
Any help as to why those errors might appear?
Cheers,
Ian
You need to pass materials as an argument to MeshFaceMaterials, like so:
loader.load( "js/charWalk01.js", function( geometry, materials ) {
materials[ 0 ].morphTargets = true;
mesh = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial( materials ) );
scene.add( mesh );
} );
three.js r.53
I don't undestand why this script doesn't work in IE, while it works in Firefox and Chrome. When I try to use this script in IE, I get this message "ACTIVEX stop script".
Please help me.
<!DOCTYPE html>
<html>
<head>
<title>Getting Started with Three.js</title>
<script type="text/javascript" src="http://www.html5canvastutorials.com/libraries/Three.js"></script>
<script type="text/javascript">
window.onload = function() {
var renderer = new THREE.WebGLRenderer();
renderer.setSize( 800, 600 );
document.body.appendChild( renderer.domElement );
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(
35, // Field of view
800 / 600, // Aspect ratio
0.1, // Near plane
10000 // Far plane
);
camera.position.set( 15, 10, 10 );
camera.lookAt( scene.position );
scene.add( camera );
var cube = new THREE.Mesh(
new THREE.CubeGeometry( 5, 5, 5 ),
new THREE.MeshLambertMaterial( { color: 0xFF0000 } )
);
scene.add( cube );
var light = new THREE.PointLight( 0xFFFF00 );
light.position.set( 10, 0, 10 );
scene.add( light );
renderer.render( scene, camera );
};
</script>
</head>
<body></body>
The Three.js WebGLRenderer doesn't work in IE (no WebGL support)
try
var renderer = new THREE.CanvasRenderer()
instead
As an alternative to the very simple solution above you can utilize alteredq and mrdoob's great Detector.js script that is included with the examples for three.js. If you use code like below you can use the WebGLRenderer as default and use canvas only if WebGL is not available. You can also use a flag like webglEnabled in order to set other options depending on your renderer later in your code.
var webglEnabled = false;
var webglReq = false;
if (Detector.webgl) {
renderer = new THREE.WebGLRenderer(
{
antialias: true,
preserveDrawingBuffer: true
}); // allow screenshot
webglEnabled = true; // set flag
}
else if (webglReq) { Detector.addGetWebGLMessage(); return false; }
else {
renderer = new THREE.CanvasRenderer();
}
renderer.setClearColorHex(0x000000, 1);
renderer.setSize(window.innerWidth, window.innerHeight);