Trying to make Three.js Boxplot Responsive - javascript

I built a simple three.js boxplot that loads individual jpgs for each mesh (bar). The boxplot looks fine on desktop, however on mobile it looks stretched / distorted. Is there a best method to make this responsive?
For the sake of simplicity, I will use an example public url for each mesh.
Here is my code:
<canvas id="threeBoxPlot"></canvas>
#threeBoxPlot {
position: absolute;
top: 10500px;
left: 100px;
width: 100%;
height: 100%;
display: block;
}
initiateThree();
function initiateThree() {
let scene, camera, renderer;
let cubeGroup;
init();
animate();
function init() {
const data = [
[49, 33, 30],
[27, 17, 13],
[9, 8, 5, 2]
]
var i = 1;
width = 500
height = 500
fov = 9
aspect = 1/5
near = .1
far = 1000
color = 0x828282
density = 0.1
loader = new THREE.TextureLoader()
scene = new THREE.Scene(); // ADDED
camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
//camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.position.set(50, 30, 50);
camera.lookAt( scene.position );
cubeGeometries = data.map(row => {
return row.map(c => {
//return new THREE.BoxGeometry( 0.2, c/max, 0.2 );
return new THREE.BoxBufferGeometry(0.2, c / 8, 0.2);
})
})
var materialArray = [];
const cubeMaterialEight = new THREE.MeshBasicMaterial({
map: new
THREE.TextureLoader().load('http://content.internetvideoarchive.com/content/photos/
1428/06000501_.jpg')
});
cubeMaterialEight.color.convertSRGBToLinear();
const cubeMaterialThree = new THREE.MeshBasicMaterial({
map: new
THREE.TextureLoader().load('http://content.internetvideoarchive.com/content/photos/
1428/06000501_.jpg')
});
cubeMaterialThree.color.convertSRGBToLinear();
const cubeMaterialTwo = new THREE.MeshBasicMaterial({
map: new
THREE.TextureLoader().load('http://content.internetvideoarchive.com/content/photos/
1428/06000501_.jpg')
});
cubeMaterialTwo.color.convertSRGBToLinear();
const cubeMaterialSeven = new THREE.MeshBasicMaterial({
map: new
THREE.TextureLoader().load('http://content.internetvideoarchive.com/content/photos/
1428/06000501_.jpg')
});
cubeMaterialSeven.color.convertSRGBToLinear();
const cubeMaterial = new THREE.MeshBasicMaterial({
map: new
THREE.TextureLoader().load('http://content.internetvideoarchive.com/content/photos/
1428/06000501_.jpg')
});
cubeMaterial.color.convertSRGBToLinear();
const cubeMaterialTen = new THREE.MeshBasicMaterial({
map: new
THREE.TextureLoader().load('http://content.internetvideoarchive.com/content/photos/
1428/06000501_.jpg')
});
cubeMaterialTen.color.convertSRGBToLinear();
const cubeMaterialNine = new THREE.MeshBasicMaterial({
map: new
THREE.TextureLoader().load('http://content.internetvideoarchive.com/content/photos/
1428/06000501_.jpg')
});
cubeMaterialNine.color.convertSRGBToLinear();
const cubeMaterialFive = new THREE.MeshBasicMaterial({
map: new
THREE.TextureLoader().load('http://content.internetvideoarchive.com/content/photos/
1428/06000501_.jpg')
});
cubeMaterialFive.color.convertSRGBToLinear();
const cubeMaterialFour = new THREE.MeshBasicMaterial({
map: new
THREE.TextureLoader().load('http://content.internetvideoarchive.com/content/photos/
1428/06000501_.jpg')
});
cubeMaterialFour.color.convertSRGBToLinear();
const cubeMaterialSix = new THREE.MeshBasicMaterial({
map: new
THREE.TextureLoader().load('http://content.internetvideoarchive.com/content/photos/
1428/06000501_.jpg')
});
cubeMaterialSix.color.convertSRGBToLinear();
materialArray.push(cubeMaterialEight, cubeMaterialThree, cubeMaterialTwo,
cubeMaterialSeven, cubeMaterial, cubeMaterialTen, cubeMaterialNine, cubeMaterialFive,
cubeMaterialFour, cubeMaterialSix);
materialIndex = -1;
const cubeMeshes = cubeGeometries.map(row => {
return row.map((cubeGeometry, index) => {
materialIndex += 1;
return new THREE.Mesh(cubeGeometry, materialArray[materialIndex]);
}
)
});
cubeGroup = new THREE.Group();
data.forEach((row, i, iarr) => {
row.forEach((d, j, jarr) => {
cubeMeshes[i][j].position.set(
i / iarr.length - 0.5,
//d/max*0.5-0.6,
d / 8 * 0.5 - 0.6,
j / jarr.length - 0.5);
//cubeMeshes[i][j].scale.set(1,4,1);
cubeGroup.add(cubeMeshes[i][j]);
})
})
const mainLight = new THREE.DirectionalLight(0xffffff, 5.0);
mainLight.position.set(10, 10, 10);
mainLight.castShadow = true;
mainLight.shadowCameraVisible = true;
mainLight.shadow.radius = 8;
const ambientLight = new THREE.HemisphereLight(0xddeeff, 0x202020, 3);
var material = new THREE.LineBasicMaterial({
color: 0x0000ff
});
scene.add(cubeGroup);
scene.add(mainLight);
scene.add(ambientLight);
scene.fog = new THREE.Fog(color, near, far);
scene.background = new THREE.Color( 0x000000 );
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.outputEncoding = THREE.sRGBEncoding;
renderer.physicallyCorrectLights = true;
renderer.domElement.id = 'threeBoxPlot';
document.body.appendChild(renderer.domElement); //ADDED
}
function animate() {
requestAnimationFrame( animate );
cubeGroup.rotation.y += 0.01;
renderer.setClearColor( 0xffffff );
renderer.render( scene, camera );
}
}

When the browser window is resized, you should re-calculate the camera's aspect ratio, and resize the renderer. This is the standard that all Three.js examples use:
window.addEventListener( 'resize', onWindowResize, false );
function onWindowResize() {
// Update camera
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
// Update renderer
renderer.setSize( window.innerWidth, window.innerHeight );
}

Related

Three.js - How to update a PlaneBufferGeometry?

I'm trying to create an ocean for my Three.js application. I took the example from this site:
https://codepen.io/RemiRuc/pen/gJMwOe?fbclid=IwAR2caTQL-AOPE2Gv6x4rzSWBrOmAh2j-raqesOO0XbYQAuSG37imbMszSis
var params = {
res : 32,
speed : 8,
amp : 2,
wireframe : true,
backgroundColor : 0x9c81e3,
planeColor : 0x4a4a4a
}
var scene = new THREE.Scene();
scene.background = new THREE.Color(params.backgroundColor)
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 )
let canvas = document.getElementById("webgl")
var renderer = new THREE.WebGLRenderer({canvas:canvas, antialias: true})
renderer.setSize( window.innerWidth, window.innerHeight )
var simplex = new SimplexNoise()
var light = new THREE.AmbientLight( 0xcccccc ); // soft white light
scene.add( light );
var pointLight = new THREE.PointLight( 0xeeeeee, 1, 100 );
pointLight.position.set( 0, 20, -20 );
scene.add( pointLight );
let geometry, material, plane
createPlane()
camera.position.z = 5;
camera.position.y = 3;
camera.lookAt(new THREE.Vector3( 0, 3, 0 ))
var animate = function () {
requestAnimationFrame( animate );
for (var i = 0; i < geometry.vertices.length; i++) {
var z = (i + Date.now() * params.speed/100000)
geometry.vertices[i].z = simplex.noise4D(z,z,z,z) * params.amp
plane.geometry.verticesNeedUpdate = true;
}
scene.background = new THREE.Color(params.backgroundColor)
material.color = new THREE.Color(params.planeColor)
material.wireframe = params.wireframe
camera.rotation.y += 0.001
renderer.render( scene, camera );
};
animate();
function createPlane(){
geometry = new THREE.PlaneGeometry( 200, 200, params.res,params.res );
material = new THREE.MeshLambertMaterial( {color: params.planeColor, side: THREE.DoubleSide, wireframe: params.wireframe} );
plane = new THREE.Mesh( geometry, material );
scene.add( plane );
plane.rotation.x = Math.PI/2
}
/***RESIZE***/
window.addEventListener('resize', ()=>{
document.querySelector('canvas').style.width = window.innerWidth + "px"
document.querySelector('canvas').style.height = window.innerHeight + "px"
renderer.setSize( window.innerWidth, window.innerHeight )
camera.aspect = window.innerWidth / window.innerHeight
camera.updateProjectionMatrix()
})
var gui = new dat.GUI()
var controller = gui.add(params, "res", 0, 100).name("Plane resolution")
gui.add(params, "speed", 0, 500).name("Wave speed")
gui.add(params, "amp", 0, 20).name("Wave amplitude")
gui.add(params, "wireframe", 0, 20).name("Wireframe")
gui.addColor(params, "backgroundColor").name("Background color")
gui.addColor(params, "planeColor").name("Plane color")
controller.onChange(()=>{
scene.remove(plane)
createPlane()
})
Issue is, I'm using PlaneBufferGeometry instead of PlaneGeometry, and it seems there are some differences
My code in render after creating the waterPlane
for (var i = 0; i < waterGeometry.attributes.position.count; i++) {
var z = (i + Date.now() * params.speed/100000);
waterGeometry.attributes.position[i] = simplex.noise4D(z,z,z,z) * params.amp;
}
waterGeometry.attributes.position.needsUpdate = true;
waterPlaneMesh.attributes.position.needsUpdate = true;
I'm not getting any errors, but no matter what I do, all I get is a flat wireframe plane geometry that doesn't move or anything. I think issue is in the updating of the plane?
This is an example of how you can displace vertices of a buffer geometry, using that SimplexNoise library:
body {
margin: 0;
background-color: #000;
color: #fff;
font-family: Monospace;
font-size: 13px;
line-height: 24px;
overscroll-behavior: none;
}
<script type="module">
import * as THREE from "https://cdn.skypack.dev/three#0.136.0";
import { OrbitControls } from "https://cdn.skypack.dev/three#0.136.0/examples/jsm/controls/OrbitControls";
import { createNoise3D } from "https://cdn.skypack.dev/simplex-noise";
let simplex = createNoise3D();
let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 2000);
camera.position.set(0, 0.5, 1).setLength(12);
let renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
window.addEventListener("resize", onWindowResize);
//scene.add(new THREE.GridHelper())
let controls = new OrbitControls(camera, renderer.domElement);
let light = new THREE.DirectionalLight(0xffffff, 0.5);
light.position.setScalar(1);
scene.add(light, new THREE.AmbientLight(0xffffff, 0.5));
let v3 = new THREE.Vector3();
let v2 = new THREE.Vector2();
let g = new THREE.PlaneGeometry(200, 200, 100, 100);
g.rotateX(-Math.PI *0.5);
let m = new THREE.MeshLambertMaterial({color: "aqua", wireframe: false});
let o = new THREE.Mesh(g, m);
scene.add(o);
let clock = new THREE.Clock();
renderer.setAnimationLoop(() => {
renderer.render(scene, camera);
let t = clock.getElapsedTime();
for(let i = 0; i < g.attributes.position.count; i++){
v2.fromBufferAttribute(g.attributes.uv, i).addScalar(t * 0.01).multiplyScalar(20);
let h = simplex(v2.x, v2.y, t * 0.1);
g.attributes.position.setY(i, h);
}
g.computeVertexNormals();
g.attributes.position.needsUpdate = true;
});
function onWindowResize() {
camera.aspect = innerWidth / innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(innerWidth, innerHeight);
}
</script>

Three.js - Canvas Element not displaying properly. Just see black box

I am relatively new to three.js and I am trying to replicate the following code block I found on Observable inside of a fiddle.
https://observablehq.com/#bumbeishvili/three-js-wooden-bar-chart
When I run the code, all I see is a giant black box. I thought I added the group materials and light elements properly to the scene but all that renders is blackness. Any help would be immensely appreciated.
Here is my code:
canvas {
display: block;
}
initiateThree();
function initiateThree() {
data = [
[3,2,1],
[6,5,4],
[8,7,6],
]
var i =1;
height = 500
fov = 18
//aspect = width / height
aspect = 500 / 500
near = 0.1
far = 1000
loader = new THREE.TextureLoader()
function update() {
//cubeGroup.rotation.x += 0.001;
cubeGroup.rotation.y += 0.001;
//cubeGroup.rotation.z += 0.001;
}
function render(scene) {
renderer.render(scene, camera);
}
const scene = new THREE.Scene(); // ADDED
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.set(-4, 1, 4);
//max = Math.max.apply(Math, data.map(d=>Math.max.apply(this,d)))
cubeGeometries = data.map(row=>{
return row.map(c=>{
//return new THREE.BoxGeometry( 0.2, c/max, 0.2 );
return new THREE.BoxGeometry( 0.2, c/8, 0.2 );
})
})
const cubeMaterial = new THREE.MeshStandardMaterial({
map:loader.load('https://threejsfundamentals.org/threejs/lessons/resources/
images/compressed-but-large-wood-texture.jpg')
});
cubeMaterial.color.convertSRGBToLinear();
const cubeMeshes = cubeGeometries.map(row=>{
return row.map(cubeGeometry => new THREE.Mesh( cubeGeometry, cubeMaterial ))
})
const cubeGroup = new THREE.Group();
data.forEach((row,i,iarr)=>{
row.forEach((d,j,jarr)=>{
cubeMeshes[i][j].position.set(
i/iarr.length-0.5,
//d/max*0.5-0.6,
d/8*0.5-0.6,
j/jarr.length-0.5);
//cubeMeshes[i][j].scale.set(1,4,1);
cubeGroup.add(cubeMeshes[i][j]);
})
})
const mainLight = new THREE.DirectionalLight(0xffffff, 3.0);
mainLight.position.set(10, 10, 10);
const ambientLight = new THREE.HemisphereLight(0xddeeff, 0x202020, 3);
//scene.add(cubeMeshes); //Not This One?
scene.add(cubeGroup);
scene.add(mainLight);
scene.add(ambientLight);
const renderer = new THREE.WebGLRenderer({
antialias: true
});
//renderer.setSize(width, height);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.gammaFactor = 2.2;
renderer.gammaOutput = true;
renderer.physicallyCorrectLights = true;
document.body.appendChild( renderer.domElement ); //ADDED
}
Here is my fiddle:
https://jsfiddle.net/bullybear/m826gkrt/326/
A few things are missing in your code:
There is no animation loop.
The camera does not look at the boxes.
Also upgraded to the latest version of three.js (r118) and removed legacy code.
let scene, camera, renderer;
let cubeGroup;
init();
animate();
function init() {
const data = [
[3, 2, 1],
[6, 5, 4],
[8, 7, 6],
]
var i = 1;
height = 500
fov = 18
//aspect = width / height
aspect = 500 / 500
near = 0.1
far = 1000
loader = new THREE.TextureLoader()
scene = new THREE.Scene(); // ADDED
camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.set(-4, 1, 4);
camera.lookAt( scene.position );
//max = Math.max.apply(Math, data.map(d=>Math.max.apply(this,d)))
cubeGeometries = data.map(row => {
return row.map(c => {
//return new THREE.BoxGeometry( 0.2, c/max, 0.2 );
return new THREE.BoxBufferGeometry(0.2, c / 8, 0.2);
})
})
const cubeMaterial = new THREE.MeshStandardMaterial({
map: loader.load('https://threejsfundamentals.org/threejs/lessons/resources/images/compressed-but-large-wood-texture.jpg')
});
cubeMaterial.color.convertSRGBToLinear();
const cubeMeshes = cubeGeometries.map(row => {
return row.map(cubeGeometry => new THREE.Mesh(cubeGeometry, cubeMaterial))
})
cubeGroup = new THREE.Group();
data.forEach((row, i, iarr) => {
row.forEach((d, j, jarr) => {
cubeMeshes[i][j].position.set(
i / iarr.length - 0.5,
//d/max*0.5-0.6,
d / 8 * 0.5 - 0.6,
j / jarr.length - 0.5);
//cubeMeshes[i][j].scale.set(1,4,1);
cubeGroup.add(cubeMeshes[i][j]);
})
})
const mainLight = new THREE.DirectionalLight(0xffffff, 3.0);
mainLight.position.set(10, 10, 10);
const ambientLight = new THREE.HemisphereLight(0xddeeff, 0x202020, 3);
scene.add(cubeGroup);
scene.add(mainLight);
scene.add(ambientLight);
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.outputEncoding = THREE.sRGBEncoding;
renderer.physicallyCorrectLights = true;
document.body.appendChild(renderer.domElement); //ADDED
}
function animate() {
requestAnimationFrame( animate );
cubeGroup.rotation.y += 0.001;
renderer.render( scene, camera );
}
body {
margin: 0;
}
canvas {
display: block;
}
<script src="https://cdn.jsdelivr.net/npm/three#0.118.3/build/three.js"></script>

How to reflect an image on a IcosahedronGeometry in three.js?

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>

How to create an infinite floor (skyline) in Three.js?

QUESTION:
So I came across this:
https://skin-tracker.com/pubg/outfit?no=000000000000000000000000000&set=1&char=1
I have the central ground area which is textured already in my code. But I have no idea how to make it extend up to the horizon like seen in the link.
It seems the person who coded what you see in the link hit some kind of limitation and had to use a single color for what extends beyond the central floor area.
How can I make my floor extend to the horizon/ create a skyline ?
CODE:
var floorTexture = new THREE.ImageUtils.loadTexture( '../../public/assets/grassTile.jpg' );
floorTexture.wrapS = floorTexture.wrapT = THREE.RepeatWrapping;
floorTexture.repeat.set( 10, 10 );
var floorMaterial = new THREE.MeshBasicMaterial({ map: floorTexture, side: THREE.DoubleSide });
var floorGeometry = new THREE.PlaneGeometry(1000, 1000, 10, 10);
var mesh = new THREE.Mesh(floorGeometry, floorMaterial);
mesh.rotation.x = - Math.PI / 2;
mesh.receiveShadow = true;
scene.add( mesh );
You can simply create an enormous textured plane. I found no limitations with the example below. If you implement something like this and encounter errors/problems, update your question with the errors you're seeing.
// prepare the renderer
let WIDTH
let HEIGHT
let aspectRatio = function() {
return WIDTH / HEIGHT
}
const renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
})
document.body.appendChild(renderer.domElement)
const camera = new THREE.PerspectiveCamera(32, aspectRatio(), 1, 1000)
camera.position.set(0, 10, 50)
function resize() {
WIDTH = window.innerWidth
HEIGHT = window.innerHeight
renderer.setSize(WIDTH, HEIGHT)
camera.aspect = aspectRatio()
camera.updateProjectionMatrix()
}
resize()
window.addEventListener("resize", resize)
const scene = new THREE.Scene()
const light = new THREE.DirectionalLight(0xffffff, 1, Infinity)
light.position.set(0, 0, 1)
camera.add(light)
scene.add(camera)
const sun = new THREE.DirectionalLight(0xffffcc)
sun.position.set(0, 1, 0)
scene.add(sun)
// populate the scene
let geo = new THREE.BoxBufferGeometry(10, 10, 10)
let mat = new THREE.MeshLambertMaterial({
color: "red"
})
let mesh = new THREE.Mesh(geo, mat)
scene.add(mesh)
let tex = new THREE.TextureLoader().load("https://upload.wikimedia.org/wikipedia/commons/4/4c/Grass_Texture.png")
tex.anisotropy = 32
tex.repeat.set(100, 100)
tex.wrapT = THREE.RepeatWrapping
tex.wrapS = THREE.RepeatWrapping
geo = new THREE.PlaneBufferGeometry(10000, 10000)
mat = new THREE.MeshLambertMaterial({
map: tex
})
mesh = new THREE.Mesh(geo, mat)
mesh.position.set(0, -5, 0)
mesh.rotation.set(Math.PI / -2, 0, 0)
scene.add(mesh)
let axis = new THREE.Vector3(0, 1, 0)
function updateCamera() {
camera.position.applyAxisAngle(axis, 0.01)
}
// rendering functions
function render() {
renderer.render(scene, camera)
camera.lookAt(scene.position)
}
let animationLoopId = null
function animationLoop() {
animationLoopId = requestAnimationFrame(animationLoop)
updateCamera()
render()
}
animationLoop()
html,
body {
padding: 0;
margin: 0;
overflow: hidden;
background: skyBLue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/97/three.js"></script>

create a 3D object by adding a default height javascript

I have this code which should create a 3D form. The idea is that I have whatever coordinates stored into a vector in the same plan to which I should add a default height in order to make it 3D. As you can see I am a beginner in programming and this is the first time I use ThreeJS so can you tell me what am I doing wrong? Honestly I have no clue and I would like to know if there is another way of adding the default height to my 2D vector coordinates in order to make it 3D without using ThreeJS. Thank you!
$(document).ready(function(){
function storeCoordinate(x, y, array) {
array.push(x);
array.push(y);
}
var coords = [];
var z=500;
storeCoordinate(3, 5, coords);
storeCoordinate(10, 100, coords);
storeCoordinate(30, 120, coords);
storeCoordinate(3, 5, coords);
for (var i = 0; i < coords.length; i+=2) {
var x = coords[i];
var y = coords[i+1];
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
var shape = new THREE.Shape( coords );
ctx.moveTo(coords[i],coords[i+1]);
ctx.lineTo(coords[i+2],coords[i+3]);
ctx.stroke();
}
var render,mycanvas,scene,camera,renderer,light;
init();
animate();
function init(){
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 1, 1000 );
var extrudedGeometry = new THREE.ExtrudeGeometry(shape, {amount: 5, bevelEnabled: false});
var extrudedMesh = new THREE.Mesh(extrudedGeometry, new THREE.MeshPhongMaterial({color: 0xff0000}));
scene.add(extrudedMesh);
document.body.onmousemove = function(e){
extrudedMesh.rotation.z = e.pageX / 100;
extrudedMesh.rotation.x = e.pageY / 100;
}
//lights
dirLight = new THREE.DirectionalLight(0xffffff);
dirLight.intensity = .9;
dirLight.position.set(500, 140, 500);
dirLight.castShadow = true;
dirLight.shadowMapHeight = 2048
dirLight.shadowMapWidth = 2048
dirLight.shadowDarkness = .15
spotLight = new THREE.PointLight( 0xffffff );
spotLight.intensity = .5
spotLight.position.set( -500, 140, -500 );
camera.add( spotLight)
camera.add(dirLight);
lighthelper = new THREE.DirectionalLightHelper(dirLight, 20);
lighthelper.children[1].material.color.set(0,0,0)
lighthelper.visible = false;
scene.add(lighthelper);
ambientLight = new THREE.AmbientLight( 0x020202, 1 );
scene.add( ambientLight );
light = new THREE.PointLight(0xffffff);
light.position.set(-100,200,100);
scene.add(light);
renderer = new THREE.WebGLRenderer({canvas: mycanvas});
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.autoRotate = true;
controls.enableZoom = true;
controls.enablePan = true;
controls.rotateSpeed = 3.0;
controls.zoomSpeed = 1.0;
controls.panSpeed = 2.0;
controls.enableDamping = true;
controls.dampingFactor = 0.25;
controls.minDistance = 1.1;
controls.maxDistance = 1000;
controls.keys = [65, 83, 68]; // [ rotateKey, zoomKey, panKey ]
}
function animate() {
window.requestAnimationFrame( animate );
render();
}
function render() {
renderer.render( scene, camera );
}
var loader = new THREE.OBJLoader();
});
Just an option of how you can do it, using THREE.ExtrudeGeometry():
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 0, 3);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
var grid = new THREE.GridHelper(5, 10, "white", "gray");
grid.geometry.rotateX(Math.PI * 0.5);
scene.add(grid);
var points = [
new THREE.Vector2(0, 1),
new THREE.Vector2(1, 1),
new THREE.Vector2(1, 0)
]
var shape = new THREE.Shape(points);
var extrudeGeom = new THREE.ExtrudeGeometry(shape, {
amount: 0.5,
bevelEnabled: false
});
var mesh = new THREE.Mesh(extrudeGeom, new THREE.MeshBasicMaterial({
color: "aqua",
wireframe: true
}));
scene.add(mesh);
render();
function render() {
requestAnimationFrame(render)
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/92/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

Categories