Related
Blending multiple transparent meshes causes strange behavior: only the first mesh is drawn, the inner meshes are hidden at the intersection. This only happens within a certain camera angle range.
Can is be fixed? Why does this only happen at certain angles?
Tested with r142 and r143. Browser Chrome 104.0.5112.81.
Partially expected behaviour:
Strange blending:
Expected behaviour:
canvas {
position: absolute;
top: 0;
left: 0;
}
<script type="importmap">
{
"imports": {
"three": "https://unpkg.com/three#0.142.0/build/three.module.js",
"OrbitControls": "https://unpkg.com/three#0.142.0/examples/jsm/controls/OrbitControls.js"
}
}
</script>
<script type="module">
import * as THREE from "three";
import { OrbitControls } from "OrbitControls";
/* -- */
const renderer = new THREE.WebGLRenderer();
document.body.appendChild(renderer.domElement);
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x111111);
const ambientLight = new THREE.AmbientLight(0xffffff);
scene.add(ambientLight);
const camera = new THREE.PerspectiveCamera(75, 1, 0.1, 1000);
camera.position.set(0, 0, 5);
const controls = new OrbitControls(camera, renderer.domElement);
/* -- */
const length = 7;
const points = [
new THREE.Vector3(0, -length / 2, 0),
new THREE.Vector3(0, length / 2, 0)
];
const curve = new THREE.CatmullRomCurve3(points);
const createMeshOnScene = (scene, geometry, material, position) => {
const mesh = new THREE.Mesh(geometry, material);
mesh.position.copy(position);
scene.add(mesh);
return mesh;
};
const transparentMaterial = (color) => {
return new THREE.MeshStandardMaterial({
color: color,
side: THREE.DoubleSide,
transparent: true,
opacity: 0.6,
metalness: 0,
roughness: 1
});
};
const opaqueMaterial = new THREE.MeshStandardMaterial({
color: 0xffffff,
metalness: 0,
roughness: 1
});
createMeshOnScene(
scene,
new THREE.TubeGeometry(curve, 2, 0.2, 16),
opaqueMaterial,
new THREE.Vector3(0, -0.4, 0)
);
createMeshOnScene(
scene,
new THREE.ConeGeometry(2, 2, 4, 1, true, 0, Math.PI * 1.6),
transparentMaterial(0xaa0000),
new THREE.Vector3(0, 0, 0)
);
createMeshOnScene(
scene,
new THREE.ConeGeometry(2, 2, 4, 1, true, 0, Math.PI * 1.6),
transparentMaterial(0xaaaa00),
new THREE.Vector3(0, -0.3, 0)
);
createMeshOnScene(
scene,
new THREE.ConeGeometry(2, 2, 4, 1, true, 0, Math.PI * 1.6),
transparentMaterial(0x00aa00),
new THREE.Vector3(0, -0.6, 0)
);
createMeshOnScene(
scene,
new THREE.ConeGeometry(2, 2, 4, 1, true, 0, Math.PI * 1.6),
transparentMaterial(0x00aaaa),
new THREE.Vector3(0, -0.9, 0)
);
/* -- */
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
/* -- */
window.addEventListener("resize", resize);
function resize() {
let width = window.innerWidth;
let height = window.innerHeight;
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.setSize(width, height);
}
resize();
</script>
The title pretty much says it all. I expect trackerballcontrols to behave like this example but for some reason I cannot rotate the camera only zoom in and out. Ovbiously I would like to be able to rotate the camera. Here's the code.
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
</head>
<body>
<h1>FooBarBaz</h1>
<p>LaDeDa</p>
<script src="http://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/TrackballControls.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.setSize( window.innerWidth, window.innerHeight );
var objects = [
{
name : "earth",
mesh : new THREE.Mesh(new THREE.SphereGeometry(1, 32, 32), new THREE.MeshPhongMaterial()),
init : function(scene){
this.mesh.position.set(0,0,0);
//this.material.map = THREE.ImageUtils.loadTexture('../earth.jpg');
scene.add(this.mesh);
},
animate : function(t){return}
},
{
name : "satellite",
mesh : new THREE.Mesh(new THREE.SphereGeometry(0.1, 32, 32), new THREE.MeshPhongMaterial()),
init : function(scene){
this.mesh.position.set(1.5,0,0);
//this.material.map = THREE.ImageUtils.loadTexture('../earth.jpg');
scene.add(this.mesh);
},
animate : function(t){this.mesh.position.set(Math.sin(t)*1.5,Math.cos(t)*1.5,0);}
}];
objects.forEach(object => object.init(scene));
var light = new THREE.HemisphereLight(0xf6e86d, 0x404040, 0.5);
scene.add(light);
camera.position.x = 0;
camera.position.y = -5;
camera.position.z = 0;
camera.lookAt(new THREE.Vector3( 0, 0, 0));
var timeStep = 0.01;
var time = 0;
var controls = new THREE.TrackballControls( camera, renderer.domElement );
controls.target.set( 0, 0, 0 );
var render = function () {
time += timeStep;
requestAnimationFrame( render );
objects.forEach(object => object.animate(time));
controls.update();
renderer.render(scene, camera);
}
document.body.appendChild( renderer.domElement );
render();</script>
</body>
</html>
There are two points in your code need adjustment.
You need to append renderer.domElement to body before initializing controls:
document.body.appendChild(renderer.domElement);
var controls = new THREE.TrackballControls(camera, renderer.domElement);
Since you make your camera.position on y-axis, and in TrackballControls camera.up is default set to y-axis, this makes your controls unable to work porperly. So what you need to do is to change the default camera.up behaviour:
camera.up = new THREE.Vector3(1, 1, 1);//you can change the values freely ,just dont make it parallel to y-axis
Sorry I'm not a ThreeJS expert, you can refer to this for more information:https://github.com/mrdoob/three.js/issues/10161
So the code below works fine:
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
</head>
<body>
<h1>FooBarBaz</h1>
<p>LaDeDa</p>
<script src="http://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/TrackballControls.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.setSize(window.innerWidth, window.innerHeight);
var objects = [
{
name: "earth",
mesh: new THREE.Mesh(new THREE.SphereGeometry(1, 32, 32), new THREE.MeshPhongMaterial()),
init: function (scene) {
this.mesh.position.set(0, 0, 0);
//this.material.map = THREE.ImageUtils.loadTexture('../earth.jpg');
scene.add(this.mesh);
},
animate: function (t) { return }
},
{
name: "satellite",
mesh: new THREE.Mesh(new THREE.SphereGeometry(0.1, 32, 32), new THREE.MeshPhongMaterial()),
init: function (scene) {
this.mesh.position.set(1.5, 0, 0);
//this.material.map = THREE.ImageUtils.loadTexture('../earth.jpg');
scene.add(this.mesh);
},
animate: function (t) { this.mesh.position.set(Math.sin(t) * 1.5, Math.cos(t) * 1.5, 0); }
}];
objects.forEach(object => object.init(scene));
var light = new THREE.HemisphereLight(0xf6e86d, 0x404040, 0.5);
scene.add(light);
camera.position.x = 0;
camera.position.y = -5;
camera.position.z = 0;
camera.up = new THREE.Vector3(1, 1, 1);
camera.lookAt(new THREE.Vector3(0, 0, 0));
var timeStep = 0.01;
var time = 0;
document.body.appendChild(renderer.domElement);
var controls = new THREE.TrackballControls(camera, renderer.domElement);
controls.target.set(0, 0, 0);
var render = function () {
time += timeStep;
requestAnimationFrame(render);
objects.forEach(object => object.animate(time));
controls.update();
renderer.render(scene, camera);
}
render();</script>
</body>
</html>
I would like to make IcosahedronGeometry in three.js and reflect an image on the front side of the geometry.
I already made a IcosahedronGeometry and made it rotate on it's axis.
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
// RENDERER
var renderer = new THREE.WebGLRenderer({
antialias: true
});
// RENDERER - SIZE OF CANVAS
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor('#ffffff');
document.body.appendChild(renderer.domElement);
// RESPONSIVE RENDERING
window.addEventListener('resize', () => {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
});
var groundMaterial = new THREE.MeshPhongMaterial({
shininess: 100,
color: 0xffffff,
specular: 0xffffff
});
const cubeCamera = new THREE.CubeCamera(75, 1000, 512);
scene.add(cubeCamera);
// GEOMETRY
var geometry = new THREE.IcosahedronGeometry(2, 1);
var material = new THREE.MeshStandardMaterial({
color: 0x98bbbd,
side: THREE.FrontSides,
roughness: 1,
metalness: 0.5,
envMap: cubeCamera.renderTarget
});
material.roughness = 0;
material.metalness = 1;
material.flatShading = true;
material.envMap = cubeCamera.renderTarget.texture;
var sphere = new THREE.Mesh(geometry, material);
scene.add(sphere);
console.log(sphere.position);
console.log(cubeCamera.position);
cubeCamera.position.copy(sphere.position);
cubeCamera.update(renderer, scene);
// FLOOR
var floorTexture = new THREE.ImageUtils.loadTexture('images/woman.png');
// floorTexture.wrapS = floorTexture.wrapT = THREE.RepeatWrapping;
// floorTexture.repeat.set(1000, 1000);
var floorMaterial = new THREE.MeshBasicMaterial({
map: floorTexture,
side: THREE.BackSide
});
var floorGeometry = new THREE.PlaneGeometry(5, 5, 1, 1);
var floor = new THREE.Mesh(floorGeometry, floorMaterial);
floor.position.y = 0;
floor.position.x = 0;
floor.position.z = 3;
scene.add(floor);
cubeCamera.lookAt(floor);
// CONTROLS
var orbit = new THREE.OrbitControls(camera, renderer.Mesh);
camera.position.z = 5;
// LIGHTS
var topLeftLight = new THREE.PointLight(0xffffff, 1, 1);
topLeftLight.position.set(-50, 50, -25);
scene.add(topLeftLight);
var topRightLight = new THREE.PointLight(0xffffff, 1, 10);
topRightLight.position.set(50, 150, -25);
scene.add(topRightLight);
var lightBottomRight = new THREE.PointLight(0xffffff, 1, 100);
lightBottomRight.position.set(40, -50, 25);
scene.add(lightBottomRight);
var lightBottomLeft = new THREE.PointLight(0xffffff, 1, 100);
lightBottomLeft.position.set(-40, -50, 25);
scene.add(lightBottomLeft);
var lightTopRight = new THREE.PointLight(0xffffff, 1, 100);
lightTopRight.position.set(40, 50, 25);
scene.add(lightTopRight);
var lightTopLeft = new THREE.PointLight(0xffffff, 1, 100);
lightTopLeft.position.set(-40, 50, 25);
scene.add(lightTopLeft);
var backLight = new THREE.PointLight(0xffffff, 1, 100);
backLight.position.set(0, 0, -25);
scene.add(backLight);
var light = new THREE.AmbientLight(0x404040, 2); // soft white light
scene.add(light);
// update function
function render() {
requestAnimationFrame(render);
sphere.rotation.x += 0.005;
sphere.rotation.y += 0.005;
sphere.visible = false;
cubeCamera.update(renderer, scene);
sphere.visible = true;
renderer.render(scene, camera);
}
render();
I would like to see a rotating IcosahedronGeometry which reflects an image on the front side. I tried adding a cube camera and pointing it at the PlaneGeometry with an image texture but nothing is reflecting.
I would like to simulate something like this, but it doesn't have to be exactly the same.
The desired result.
3 issues.
you have to call cubeCamera.update before you access cubeCamera.renderTarget.texture
The parameters to CubeCamera are new CubeCamera(near, far, size).
The code had new CubeCamera(75, 1000, 512) which means only things 75 to 1000 units away from the camera would be visible. The image plane you had is 3 units away so would not be visible.
You don't call lookAt with the CubeCamera as it's always looking in all directions.
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
// RENDERER
var renderer = new THREE.WebGLRenderer({
antialias: true
});
// RENDERER - SIZE OF CANVAS
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor('#ffffff');
document.body.appendChild(renderer.domElement);
// RESPONSIVE RENDERING
window.addEventListener('resize', () => {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
});
var groundMaterial = new THREE.MeshPhongMaterial({
shininess: 100,
color: 0xffffff,
specular: 0xffffff
});
const cubeCamera = new THREE.CubeCamera(0.001, 10, 512);
scene.add(cubeCamera);
// GEOMETRY
var geometry = new THREE.IcosahedronGeometry(2, 1);
var material = new THREE.MeshStandardMaterial({
color: 0x98bbbd,
side: THREE.FrontSide,
roughness: 1,
metalness: 0.5,
});
cubeCamera.update(renderer, scene);
material.roughness = 0;
material.metalness = 1;
material.flatShading = true;
material.envMap = cubeCamera.renderTarget.texture;
var sphere = new THREE.Mesh(geometry, material);
scene.add(sphere);
// FLOOR
var loader = new THREE.TextureLoader();
var floorTexture = loader.load('https://i.imgur.com/UKBsvV0.jpg');
var floorMaterial = new THREE.MeshBasicMaterial({
map: floorTexture,
side: THREE.BackSide
});
var floorGeometry = new THREE.PlaneGeometry(5, 5, 1, 1);
var floor = new THREE.Mesh(floorGeometry, floorMaterial);
floor.position.y = 0;
floor.position.x = 0;
floor.position.z = 3;
scene.add(floor);
// CONTROLS
var orbit = new THREE.OrbitControls(camera, renderer.Mesh);
camera.position.z = 5;
// LIGHTS
var topLeftLight = new THREE.PointLight(0xffffff, 1, 1);
topLeftLight.position.set(-50, 50, -25);
scene.add(topLeftLight);
var topRightLight = new THREE.PointLight(0xffffff, 1, 10);
topRightLight.position.set(50, 150, -25);
scene.add(topRightLight);
var lightBottomRight = new THREE.PointLight(0xffffff, 1, 100);
lightBottomRight.position.set(40, -50, 25);
scene.add(lightBottomRight);
var lightBottomLeft = new THREE.PointLight(0xffffff, 1, 100);
lightBottomLeft.position.set(-40, -50, 25);
scene.add(lightBottomLeft);
var lightTopRight = new THREE.PointLight(0xffffff, 1, 100);
lightTopRight.position.set(40, 50, 25);
scene.add(lightTopRight);
var lightTopLeft = new THREE.PointLight(0xffffff, 1, 100);
lightTopLeft.position.set(-40, 50, 25);
scene.add(lightTopLeft);
var backLight = new THREE.PointLight(0xffffff, 1, 100);
backLight.position.set(0, 0, -25);
scene.add(backLight);
var light = new THREE.AmbientLight(0x404040, 2); // soft white light
scene.add(light);
// update function
function render() {
sphere.rotation.x += 0.005;
sphere.rotation.y += 0.005;
sphere.visible = false;
cubeCamera.update(renderer, scene);
sphere.visible = true;
renderer.render(scene, camera);
requestAnimationFrame(render);
}
render();
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r105/three.min.js"></script>
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r105/js/controls/OrbitControls.js"></script>
I'm new at three.js.
In my work, I have to made 3d graphical website.
So after searched in google, I found that three.js is suitable to manipulate WebGL conveniently.
In three.js document(https://threejs.org/docs/#api/en/geometries/TextGeometry),
TextGeometry is API for draw text in the scene.
[src.js]
init = () => {
window.addEventListener('resize', resizeWindow);
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 10000);
var controls = new THREE.OrbitControls( camera );
controls.update();
var renderer = new THREE.WebGLRenderer();
renderer.setClearColor(0xdd3b56);
renderer.setSize(window.innerWidth, window.innerHeight);
// Set shadow
renderer.shadowMap.enabled = true;
// Show Axis
var axes = new THREE.AxisHelper(5);
scene.add(axes);
// Text
var loader = new THREE.FontLoader();
loader.load( './helvetiker_regular.typeface.json', function ( font ) {
var geometry = new THREE.TextGeometry( 'Hello three.js!', {
font: font,
size: 80,
height: 5,
curveSegments: 12,
bevelEnabled: true,
bevelThickness: 10,
bevelSize: 8,
bevelSegments: 5
} );
} );
var textMaterial = new THREE.MeshPhongMaterial({color: 0xFE98A0});
var text = new THREE.Mesh(geometry, textMaterial);
text.position.x = 0;
text.position.y = 10;
text.position.z = 10;
scene.add(text);
// Light
var spotLight = new THREE.SpotLight(0xFFFFFF);
spotLight.position.set(-40, 60, 30);
spotLight.castShadow = true;
spotLight.shadow.mapSize.width = 5120;
spotLight.shadow.mapSize.height = 5120;
scene.add(spotLight);
// Camera Setting
camera.position.x = 0;
camera.position.y = 30;
camera.position.z = 30;
camera.lookAt(scene.position);
document.getElementById("threejs_scene").appendChild(renderer.domElement);
renderScene();
function renderScene() {
requestAnimationFrame(renderScene);
controls.update();
renderer.render(scene, camera);
}
}
window.onload = init();
[index.html]
<html>
<head>
<script src="three.js"></script>
<script src="OrbitControls.js"></script>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div id="threejs_scene"></div>
<script src="src.js"></script>
</body>
</html>
When I execute my code, it throws [.WebGL-0x7fb612852000]RENDER WARNING: Render count or primcount is 0. and WebGL: too many errors, no more errors will be reported to the console for this context. errors.
So I searched it at google, it occured when Three.js is trying to render an object that does not exist yet.
But in my code, I already defined it.
var textMaterial = new THREE.MeshPhongMaterial({color: 0xFE98A0});
var text = new THREE.Mesh(geometry, textMaterial);
text.position.x = 0;
text.position.y = 10;
text.position.z = 10;
How can I solve this issue?
My last goal is display text in the scene.
Thanks.
window.onload = function(params) {
/*
*
* SET UP THE WORLD
*
*/
//set up the ratio
var gWidth = window.innerWidth;
var gHeight = window.innerHeight;
var ratio = gWidth / gHeight;
var borders = [40, 24] //indicate where the ball needs to move in mirror position
var light = new THREE.AmbientLight(0xffffff, 0.5);
var light1 = new THREE.PointLight(0xffffff, 0.5);
light1.position.set(0, 5, 0);
light1.castShadow = true;
// set the renderer
var renderer = new THREE.WebGLRenderer();
var camera = new THREE.PerspectiveCamera();
camera.position.set(10, 10, 10);
camera.lookAt(new THREE.Vector3(0, 0, 0));
//properties for casting shadow
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.setSize(gWidth, gHeight);
document.body.appendChild(renderer.domElement);
var scene = new THREE.Scene();
scene.add(light);
scene.add(light1);
var ground = new THREE.Mesh(new THREE.BoxGeometry(10, 0.5, 10), new THREE.MeshLambertMaterial())
ground.receiveShadow = true;
scene.add(ground)
var geometry;
var loader = new THREE.FontLoader();
var mesh;
requestAnimationFrame(render);
function render() {
if (mesh) {
mesh.rotation.y += 0.01;
mesh.rotation.z += 0.007;
}
renderer.render(scene, camera);
requestAnimationFrame(render);
}
loader.load('https://cdn.rawgit.com/mrdoob/three.js/master/examples/fonts/helvetiker_regular.typeface.json', function(font) {
var geometry = new THREE.TextGeometry('Hello three.js!', {
font: font,
size: 80,
height: 5,
curveSegments: 12,
bevelEnabled: true,
bevelThickness: 10,
bevelSize: 8,
bevelSegments: 5
});
var material = new THREE.MeshLambertMaterial({
color: 0xF3FFE2
});
mesh = new THREE.Mesh(geometry, material);
mesh.position.set(0, 2, 0);
mesh.scale.multiplyScalar(0.01)
mesh.castShadow = true;
scene.add(mesh);
var canv = document.createElement('canvas')
canv.width = canv.height = 256;
var ctx = canv.getContext('2d')
ctx.fillStyle = 'white';
ctx.fillRect(0, 0, canv.width, canv.height);
ctx.fillStyle = 'black'
ctx.fillText("HERE IS SOME 2D TEXT", 20, 20);
var tex = new THREE.Texture(canv);
tex.needsUpdate = true;
var mat = new THREE.MeshBasicMaterial({
map: tex
});
var plane = new THREE.Mesh(new THREE.PlaneGeometry(10, 10), mat);
scene.add(plane)
});
}
body {
padding: 0;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/96/three.min.js"></script>
<html>
<head>
</head>
<body>
</body>
</html>
I was trying to render text in three.js using TextGeometry but got an empty black screen. I suspected that was an issue with the camera and I added simple green box, that box was rendered correctly.
// tslint:disable-next-line:no-var-requires
const fontJson = require("./fonts/gentilis_bold.typeface.json");
import "./index.scss";
import * as THREE from "three";
(window as any).THREE = THREE;
import "./controls/OrbitControls";
const scene = new THREE.Scene();
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 0, 5);
camera.lookAt(scene.position);
const textMaterial = new THREE.MeshPhongMaterial({ color: 0x00ff00 });
console.log(new THREE.Font(fontJson))
const textGeometry = new THREE.TextGeometry("Hello amigo", {
font: new THREE.Font(fontJson),
size: 80,
height: 5,
curveSegments: 12,
bevelEnabled: true,
bevelThickness: 10,
bevelSize: 8,
});
const textMesh = new THREE.Mesh(textGeometry, textMaterial);
// const geometry = new THREE.BoxGeometry(1, 1, 1);
// const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
// const mesh = new THREE.Mesh(geometry, material);
// scene.add(mesh);
scene.add(textMesh);
const controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.addEventListener("change", () => {
renderer.render(scene, camera);
});
renderer.render(scene, camera);
I have found the problem, sorry for the delay. If you use MeshPhongMaterial texture or others (except MeshBasicMaterial) you should add some lights to your scene. Just add this lines to your scene.
const pointLight = new THREE.PointLight(0xffffff, 1.5); pointLight.position.set(0, 100, 90);
scene.add(pointLight);
pointLight.color.setHSL(Math.random(), 1, 0.5);
const textMaterials = [
new THREE.MeshPhongMaterial({ color: 0xffffff, flatShading: true }),
new THREE.MeshPhongMaterial({ color: 0xffffff }),
];