I'm doing some prototyping, and I'm displaying some data in 3D using three.js (version 68). Desired result of whole animation would be a bunch of colored balls (that represent protons and neutrons that are colored according to some schema). Everything works good, but for reasons unknown to me rendered results are pixcelated.
Current version basically looks like that (this image is ~400px wide):
I have checked all obvious things like: passing incorrect resolution, browser scaling and so forth.
You can see this issue on this fiddle, and download the webpage here.
And also here are revelant parts of code:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<script src="js/jquery.js"></script>
<script src="js/coffee-script.js"></script>
<script src="js/three.js"></script>
<script src="js/OrbitControls.js"></script>
<script src="js/animtest/load_event.js"></script>
<style>canvas { width: 100%; height: 100% }</style>
<title></title>
</head>
<body>
<div id="animation"
style="width: 1024px; height: 768px; ">
</div>
<script>
$(function(){
ctrl = new AnimController("#animation");
ctrl.set_up_scene();
ctrl.render();
ctrl.display_frame(4);
});
</script>
</body>
</html>
Here is the coffeescript code that loads the animation:
class AnimController
...
set_up_scene: () ->
#scene = new THREE.Scene()
el = $(#element_name)
#camera = new THREE.PerspectiveCamera(45
el.width()/el.height(),
1, 20000
)
#camera.position.set(100, 100, 0)
#scene.add new THREE.AmbientLight 0x111111
#renderer = new THREE.WebGLRenderer()
el.html(#renderer.domElement)
controls = new THREE.OrbitControls(#camera, #renderer.domElement );
controls.addEventListener 'change', () =>
console.log("Change")
#render()
render: () ->
requestAnimationFrame(() => #render)
console.log "Render"
if #update_scene
material = new THREE.MeshBasicMaterial() #"color": 0xffff00,
geometry = new THREE.SphereGeometry 5, 50, 50
console.log "Update"
#update_scene = false
#scene = new THREE.Scene()
for particle in #curr_event
p = particle['position']
sphere = new THREE.Mesh( geometry, material );
sphere.position.set(p[0], p[1], p[2])
#scene.add(sphere)
#renderer.render(#scene, #camera)
It seems that you have not requested antialiasing on the renderer you are using. I don't know coffeescript but in javascript you would do:
renderer = new THREE.WebGLRenderer({ antialias: true });
Antialiasing also was a factor (see #gaitat answer) but I also forgot to set resoluion the renderer:
renderer.setSize( 1024, 768 )
Related
I am learning Web AR development using MindAR, https://hiukim.github.io/mind-ar-js-doc/#:~:text=MindAR%20is%20an%20opensource%20web,are%20written%20for%20AFRAME%20integration. I am following a tutorial on Udemy, https://www.udemy.com/course/introduction-to-web-ar-development/learn/lecture/29791078#overview. But it is not working unfortunately for me but for the instructor.
This is my index.html page.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>AR Research</title>
<script src="https://cdn.jsdelivr.net/npm/mind-ar#1.1.5/dist/mindar-image.prod.js"></script>
<script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/mind-ar#1.1.5/dist/mindar-image-aframe.prod.js"></script>
<script src="./main.js" type="module">
</script>
<style>
html, body {
position: relative;
margin: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
</style>
</head>
<body>
</body>
</html>
As you can see there is not much in the code. I basically embedded the required Mind AR libraries through CDN and add the css styling a little bit and reference my main.js file.
This is my main.js file.
document.addEventListener(`DOMContentLoaded`, () => {
const start = async () => {
// create the AR world and specify the marker
const mindarThree = new window.MINDAR.IMAGE.MindARThree({
container: document.body,
imageTargetSec: './groot.mind'
})
const { renderer, scene, camera } = mindarThree;
const geometry = new THREE.PlaneGeometry(1, 1);
const material = new THREE.MeshBasicMaterial({ color: 0x0000ff, transparent: true, opacity: 0.5 });
const plane = new THREE.Mesh(geometry, material);
const anchor = mindarThree.addAnchor(0);
anchor.group.add(plane);
await mindarThree.start();
renderer.setAnimationLoop(() => {
renderer.render(scene, camera);
})
}
start();
})
When I run the code on the browser, I am getting the following error.
main.js:4 Uncaught (in promise) TypeError: MINDAR.IMAGE.MindARThree is not a constructor
at start (main.js:4:29)
at HTMLDocument.<anonymous> (main.js:24:5)
What is wrong with my code and how can I fix it?
I had the same problem. The solution is that a different MindAR package needs to be imported, the one that combines MindAR and Three.js:
Use this one:
https://cdn.jsdelivr.net/npm/mind-ar#1.1.5/dist/mindar-image-three.prod.js
Not this one:
https://cdn.jsdelivr.net/npm/mind-ar#1.1.5/dist/mindar-image.prod.js
I am trying to add a 3D object to the scene.
Uncaught TypeError: Class constructor ol cannot be invoked without 'new' at new GLTFLoader
Major line error let loader = new THREE.GLTFLoader();
But I can't figure out what to put in brackets? New? .., or what?
Constructor:
https://threejs.org/docs/#examples/en/loaders/GLTFLoader
Model 2(Mb): https://drive.google.com/file/d/1bPnC5coazNFIcsyvV9U29BFiFhXhriYg/view?usp=sharing
Source:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script src="https://cdn.rawgit.com/mrdoob/three.js/master/examples/js/loaders/GLTFLoader.js"></script>
<script>
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 10; // Отдаление камеры
renderer = new THREE.WebGLRenderer();
renderer.setClearColor(0x000000, 0);
renderer.setSize(1280 , 720);
renderer.domElement.setAttribute("id", "Church3DObj");
document.body.insertBefore(renderer.domElement, document.body.firstChild);
const aLight = new THREE.AmbientLight(0x404040, 1.2);
scene.add(aLight);
let loader = new THREE.GLTFLoader();
let obj = null;
loader.load('/3d/Church.gltf', function(gltf) {
obj = gltf;
obj.scene.scale.set(1.3, 1.3, 1.3);
scene.add(obj.scene);
});
</script>
</body>
</html>
It is telling you that you cannot invoked GLTFLoader without 'new' at new GLTFLoader
If you look at the doc you linked in the code exemple they use
const loader = new GLTFLoader(); before doing anything with it.
You must instance GLTFLoader.
To avoid this error, we must download from GitHub файлы .js:
three.js, GLTFLoader.js, OrbitControls.js, three.module.js
<script src="scripts/three.js"></script>
<script type="module"> src="scripts/GLTFLoader.js"></script>
<script type="module"> src="scripts/OrbitControls.js"></script>// IF THERE IS A CAMERA CONTROL IN SPACE
Place them in the root of the project and open GLTFLoader.js. At the time of 05/24/2021 we find 64 lines
from './smthPath/smthPath/smthPath/three.module.js';
and remove the excess. (that is, we specify the path to the three.module.js file). In my case:
from './three.module.js';
(If there is a camera control, then we do the same with the OrbitControls.js file, line 9)
from './three.module.js';
Further it is IMPORTANT in the script, in which all the brains add type = "module", and import the files - that is, it turns out
<script type="module">
import {GLTFLoader} from "./scripts/GLTFLoader.js";
import {OrbitControls} from './scripts/OrbitControls.js';
//...
</script>
IMPORTANT
*For people who have not worked with 3D on the web, but model in Cinema4D, 3Ds Max, ZBrush ... (like me). You need not only a .gltf file but also a .bin file
How do I get them?
Go to the site [Scetchfab] (https://sketchfab.com/feed).
Load the model (set the settings for free download (then
you can delete the model)).
We are waiting for it to be processed.
4.download the required format (glFT)
Remove the model from Scetchfab *
IMPORTANT
***The final view of the html file ***
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Dragon</title>
</head>
<body id="c" style="margin: 0;">
<!--3D-->
<script src="scripts/three.js"></script>
<script type="module" src="scripts/GLTFLoader.js"></script>
<script type="module" src="scripts/OrbitControls.js"></script>
<script type="module">
import {GLTFLoader} from "./scripts/GLTFLoader.js";
import {OrbitControls} from './scripts/OrbitControls.js';
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x555555);
const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 100);
camera.position.set(0, 5, 15);
const renderer = new THREE.WebGLRenderer({alpha: true, antialias: true});
renderer.setClearColor(0x000000, 0);
renderer.setSize(1920 , 1080);
document.body.appendChild(renderer.domElement);
const aLight = new THREE.AmbientLight(0x404040, 15);
aLight.position.set(0,10,10)
scene.add(aLight);
const pLight = new THREE.PointLight(0xFFFFFF, 15);
pLight.position.set(0,5,0)
scene.add(pLight);
const phelper = new THREE.PointLightHelper(pLight);
scene.add(phelper);
const loader = new GLTFLoader();
let obj = null;
loader.load("3d/Dragon/scene.gltf", function(gltf) {
obj = gltf.scene;
scene.add(gltf.scene);
});
const canvas = document.getElementById("c");
const controls = new OrbitControls(camera, canvas);
controls.target.set(0, 1, 0);
controls.update();
function animate(){
requestAnimationFrame(animate)
obj.rotation.y += 0.005;
renderer.render(scene, camera)
}
animate();
</script>
</body>
</html>
I'm following several tutorials on Three.js, yet I keep getting a Uncaught ReferenceError: OBJLoader is not defined error when trying to implement my own .obj file. Tried different methods, nothing is helping. Been stuck on this problem for days.
I'm running on localhost using http-server.
Oddly enough, when I switch the new OBJLoader(); to new THREE.ObjectLoader(); it seems to work as it tries to load the file, albeit the file is not a .json file, it is an .obj so it throws an error.
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>three.js crash course</title>
<link rel="stylesheet" href="css/styles.css">
</head>
<body>
<script type="module" src="js/jQuery.js"></script>
<script type="module" src="js/three.min.js"></script>
<script type="module" src="js/OrbitControls.js"></script>
<script type="module" src="loaders/GLTFLoader.js"></script>
<script type="module" src="loaders/OBJLoader.js"></script>
<script type="module" src="js/index.js"></script>
</body>
</html>
JS
window.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);
$(window).resize(function(){
var width = window.innerWidth;
var height = window.innerHeight;
renderer.setSize(width, height);
camera.aspect = width/height;
camera.updateProjectionMatrix();
});
var controls = new THREE.OrbitControls(camera, renderer.domElement);
const loader = new OBJLoader();
loader.load (
// resource URL
'./models/boat_large.obj',
// called when resource is loaded
function ( object ) {
scene.add( object );
},
// called when loading is in progresses
function ( xhr ) {
console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );
},
// called when loading has errors
function ( error ) {
console.log( 'An error happened' );
}
);
camera.position.z = 3;
var ambientLight = new THREE.AmbientLight(0xFFFFFF, 0.8);
// game logic
var update = () => {
};
// draw scene
var render = () => {
renderer.render(scene, camera);
};
// run game loop (update, render, repeat)
var GameLoop = () => {
requestAnimationFrame(GameLoop);
update();
render();
}
GameLoop();
}
You need to use new THREE.OBJLoader() when you reference the javascript files like that.
The reason it works in the ThreeJS example is, because it is imported via
import { OBJLoader } from './jsm/loaders/OBJLoader.js';
.
Alternatively you could include the file like it is shown in the example
.
In your case it would obviously be something like
import { OBJLoader } from '../loaders/OBJLoader.js';
assuming the JS posted above is from index.js.
it worked for me adding the following import:
import {OBJLoader} from 'three/examples/jsm/loaders/OBJLoader';
I have been working on a 3D project where we show 3D object in the web browser using Three.js Library.
The problem is:
1st the model is displayed in a small dom element or when the browser window itself is small.
Then when the window (or the dom element is resized) the model become pixelated
Following are some screenshots:
Before resize:
After resize:
How it should be after resize:
Here is the part of code that is setting the the model dimensions (height and width), and this function gets called when the resize event if fired:
console.log("domChanged fired")
instance.domBoundingBox = instance.dom.getBoundingClientRect();
instance.domCenterPos.x = instance.domBoundingBox.width / 2 + instance.domBoundingBox.left;
instance.domCenterPos.y = instance.domBoundingBox.height / 2 + instance.domBoundingBox.top;
var width = instance.dom.clientWidth, height = instance.dom.clientHeight;
instance.domWidthHalf = width / 2, instance.domHeightHalf = height / 2;
// TODO: fire event to expose it to site developers
// here we should update several values regarding width,height,position
if(instance.cameraReal) {
instance.cameraReal.aspect = instance.dom.clientWidth / instance.dom.clientHeight;
instance.cameraReal.updateProjectionMatrix();
}
if(instance.renderer3D)
instance.renderer3D.setSize(instance.dom.clientWidth, instance.dom.clientHeight);
Can anybody give me a hint? I've been working on that a couple of days already but no clue so far
So the canvas element can be resized like every other element. What you want to do is tell the render and camera to resize the contents of your canvas as well.
window.addEventListener( 'resize', onWindowResize, false );
function onWindowResize(){
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
Finally the problem were solved the actually problem was coming from because the application is using the THREE.EffectComposer object, in the class constructor a composer object were created like following:
this.composer = new THREE.EffectComposer(this.renderer3D);
So as for the renderer, the composer needed to have the size updated after the event handler function like following:
if(instance.renderer3D)
instance.renderer3D.setSize(instance.dom.clientWidth, instance.dom.clientHeight);
if(instance.composer)
instance.composer.setSize(instance.dom.clientWidth, instance.dom.clientHeight);
And this fixed the issue perfectly :)
I applied Shawn Whinnery's answer to my needs with React JS:
Start listener onMount:
componentDidMount() {
window.addEventListener('resize', this.handleResize, false)
}
Remove listener onUnmount (because we like garbage collection):
componentWillUnmount() {
window.removeEventListener('resize', this.handleResize, false)
}
Install handler function:
handleResize = () => {
this.camera.aspect = window.innerWidth / window.innerHeight
this.camera.updateProjectionMatrix()
this.renderer.setSize(window.innerWidth, window.innerHeight)
}
Fat arrow syntax is used to avoid binding this. The code will not work if you have this: handleResize() { ... }, but of course, it would work if you added this to your constructor:
this.handleResize = this.handleResize.bind(this)
Final note: confirm that your camera is this.camera and your renderer is this.renderer. Besides that, you should be able to paste it all in.
For those googling, if you want to start off quick with a helper util that does the resizing for you, check out this github: https://github.com/jeromeetienne/threex.windowresize
The only thing you have to do is install it via bower and initialise it:
new THREEx.WindowResize(renderer, camera)
It is very simple. this three.js code will not change even if resized the browser window.
Code:
//Simple Cube Example
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 0.1, 1000 );
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var geometry = new THREE.BoxGeometry( 1, 1, 1 );
var material = new THREE.MeshBasicMaterial( { color: "rgb(255, 0, 0)" } );
var cube = new THREE.Mesh( geometry, material );
scene.add( cube );
camera.position.z = 5;
var edges = new THREE.EdgesHelper( cube, "rgb(0, 0, 0)" );
edges.material.linewidth = 5;
scene.add( edges );
function animate(){
requestAnimationFrame( animate );
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render( scene, camera );
}
animate();
function rot(){
requestAnimationFrame( rot );
edges.rotation.x += 0.01;
edges.rotation.y += 0.01;
}
rot();
//this will not change it's size when browser is resized, but use css and correct it.
//this is the code. it does not work use a div and use the javascript
.code{
float: left;
width: 100vw; /*fullscreen*/
height: 100vh;
}
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="keywords" content="">
<meta name="robots" content="index, follow" />
<link rel="canonical" href="http://" />
<meta name="author" content="">
<meta name="google-site-verification" content="">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://fonts.googleapis.com/css?family=Hammersmith+One|Lato" rel="stylesheet">
<title></title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<script src="https://threejs.org/build/three.js"></script>
</body>
</html>
try antialias property to resolve pixelation problem by 50 - 70%
e.g :var renderer = new THREE.WebGLRenderer({antialias:true});
I need to work on project that uses three.js. So I have tried to learn the basic and O wrote this simple code just to see something. But it doesn't work at all and when I click to view it on web browser nothing is shown.
This is my code:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>
<script src="Three.js"></script>
</head>
<body>
<script type="text/javascript">4
var renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(document.body.clientWidth,
document.body.clientHeight);
document.body.appendChild(renderer.domElement);
renderer.setClearColorHex(0xEEEEEE, 1.0);
renderer.clear();
// new THREE.PerspectiveCamera( FOV, viewAspectRatio, zNear, zFar );
var camera = new THREE.PerspectiveCamera(45, width / height, 1, 10000);
camera.position.z = 300;
var scene = new THREE.Scene();
var cube = new THREE.Mesh(new THREE.CubeGeometry(50, 50, 50),
new THREE.MeshBasicMaterial({ color: 0x000000 }));
scene.add(cube);
renderer.render(scene, camera);
</script>
</body>
</html>
Why doesn't it work? What did I do wrong ?
Good day, could you tell us what version of Three.js your using (it shows up in the console once it loads if your not sure), and what browser your using?
A few notes, renderer.setClearColorHex is deprecated now, this should be just renderer.setClearColor.
Also you set the Camera with width / height but I dont see them defined anywhere?
Next is the camera.position.z = 300; may be too far away to see a little cube at (0, 0, 0)
Try those items and let us know if it works.
Just see this example.
http://mrdoob.github.io/three.js/examples/#webgl_geometry_cube
You are missing a main loop for cosecutive frame rendering. Also as Darryl said, what is width and height?