Scene rendering issues in three.js + imgui-js project - three.js

I have a project that is using Three.js and imgui-js. I’m trying to update to the latest version of each but I'm running into issues (they were last updated around February of 2020).
To initialize the two libraries I am calling:
await ImGui.default();
ImGui.CreateContext();
ImGui_Impl.Init(canvas);
ImGui.StyleColorsDark();
const clear_color = new ImGui.ImVec4(0.3, 0.3, 0.3, 1.00);
const renderer = new THREE.WebGLRenderer({ canvas: canvas });
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.gammaFactor = 2.2;
renderer.physicallyCorrectLights = true;
renderer.outputEncoding = THREE.sRGBEncoding;
I then add some objects to the three scene:
const scene = new THREE.Scene();
let floorDim = 1000;
var grid = new THREE.GridHelper(floorDim, 200, 'orange', 'white');
grid.name = "grid";
grid.material.opacity = 1.0;
grid.material.transparent = true;
grid.material.color.convertGammaToLinear(2.2);
grid.position.set(0, 2, 0);
scene.add(grid);
var subgrid = new THREE.GridHelper(floorDim, 600, 'grey', 'grey');
subgrid.name = "subgrid";
subgrid.material.opacity = 1.0;
subgrid.material.color.convertGammaToLinear(2.2);
subgrid.material.transparent = true;
subgrid.position.set(0, 1, 0);
scene.add(subgrid);
const light = new THREE.DirectionalLight(0xffffff, 0.8);
light.position.set(0, 100, -50);
light.lookAt(new THREE.Vector3(0, 0, 0));
scene.add(light);
const box_1_mesh = new THREE.Mesh(new THREE.BoxGeometry(5, 5, 5), new THREE.MeshLambertMaterial({ color:0x970000 }));
box_1_mesh.position.set(0, 5, 0);
scene.add(box_1_mesh);
const box_2_mesh = new THREE.Mesh(new THREE.BoxGeometry(5, 5, 5), new THREE.MeshLambertMaterial({ color:0x333000 }));
box_2_mesh.position.set(-2, 6, 7);
scene.add(box_2_mesh);
const camera = new THREE.PerspectiveCamera(50, canvas.width / canvas.height, 2, 10000);
camera.position.set(0, 10, -25);
camera.updateProjectionMatrix();
camera.lookAt(0, 0, 0);
scene.add(camera);
And call an update loop that looks like:
function _loop(time) {
ImGui_Impl.NewFrame(time);
ImGui.NewFrame();
ImGui.SetNextWindowPos(new ImGui.ImVec2(20, 20), ImGui.Cond.FirstUseEver);
ImGui.SetNextWindowSize(new ImGui.ImVec2(294, 140), ImGui.Cond.FirstUseEver);
ImGui.Begin("Visblility Toggles:");
ImGui.Checkbox("box_1 (near)", (value = box_1_mesh.visible) => box_1_mesh.visible = value);
ImGui.Checkbox("box_2 (distant)", (value = box_2_mesh.visible) => box_2_mesh.visible = value);
ImGui.Checkbox("grid", (value = grid.visible) => grid.visible = value);
ImGui.Checkbox("subgrid", (value = subgrid.visible) => subgrid.visible = value);
ImGui.End();
ImGui.EndFrame();
ImGui.Render();
renderer.setClearColor(new THREE.Color(clear_color.x, clear_color.y, clear_color.z), clear_color.w);
renderer.setSize(canvas.width, canvas.height);
camera.aspect = canvas.width / canvas.height;
camera.updateProjectionMatrix();
renderer.render(scene, camera);
ImGui_Impl.RenderDrawData(ImGui.GetDrawData());
renderer.state.reset();
window.requestAnimationFrame(_loop);
}
After updating to the latest versions of these libraries, I am getting issues where objects in the scene aren't rendering as expected.
For example, I am adding 2 GridHelpers to the scene, but for some reason only one gets displayed. Also, if the visibility of the different Three objects is toggled in the scene, for example toggling the display of one of the grids off/on, when toggled back on the object doesn't display again (and sometimes other objects disappear).
Another issue occurring is that more complex meshs' materials will have an unexpected transparency, but with the simple boxes I am adding in this example, that issue doesn’t appear to be occurring. Although, it might be relevant that the look of the boxes is changing based on whether the ImGui_Impl.RenderDrawData call is made.
I have found that if I comment out the call to ImGui_Impl.RenderDrawData(ImGui.GetDrawData()), the scene displays as expected with both grid helpers showing up so I suspect that there might be some internal conflict that is now occurring between the two libraries usages of webGl. Although it's definitely possible that I have set things up incorrectly or I am missing a call that is required.
To help demonstrate the issue, I’ve created a snippet that replicates the issue: https://codepen.io/bpeake/pen/KKNNQre.
(async function() {
await ImGui.default();
const canvas = document.getElementById("output");
const devicePixelRatio = window.devicePixelRatio || 1;
canvas.width = canvas.scrollWidth * devicePixelRatio;
canvas.height = canvas.scrollHeight * devicePixelRatio;
window.addEventListener("resize", () => {
const devicePixelRatio = window.devicePixelRatio || 1;
canvas.width = canvas.scrollWidth * devicePixelRatio;
canvas.height = canvas.scrollHeight * devicePixelRatio;
});
ImGui.CreateContext();
ImGui_Impl.Init(canvas);
ImGui.StyleColorsDark();
const clear_color = new ImGui.ImVec4(0.3, 0.3, 0.3, 1.00);
const renderer = new THREE.WebGLRenderer({ canvas: canvas });
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.gammaFactor = 2.2;
renderer.physicallyCorrectLights = true;
renderer.outputEncoding = THREE.sRGBEncoding;
const scene = new THREE.Scene();
let floorDim = 1000;
var grid = new THREE.GridHelper(floorDim, 200, 'orange', 'white');
grid.name = "grid";
grid.material.opacity = 1.0;
grid.material.transparent = true;
grid.material.color.convertGammaToLinear(2.2);
grid.position.set(0, 2, 0);
scene.add(grid);
var subgrid = new THREE.GridHelper(floorDim, 600, 'grey', 'grey');
subgrid.name = "subgrid";
subgrid.material.opacity = 1.0;
subgrid.material.color.convertGammaToLinear(2.2);
subgrid.material.transparent = true;
subgrid.position.set(0, 1, 0);
scene.add(subgrid);
const light = new THREE.DirectionalLight(0xffffff, 0.8);
light.position.set(0, 100, -50);
light.lookAt(new THREE.Vector3(0, 0, 0));
scene.add(light);
const box_1_mesh = new THREE.Mesh(new THREE.BoxGeometry(5, 5, 5), new THREE.MeshLambertMaterial({ color:0x970000 }));
box_1_mesh.position.set(0, 5, 0);
scene.add(box_1_mesh);
const box_2_mesh = new THREE.Mesh(new THREE.BoxGeometry(5, 5, 5), new THREE.MeshLambertMaterial({ color:0x333000 }));
box_2_mesh.position.set(-2, 6, 7);
scene.add(box_2_mesh);
const camera = new THREE.PerspectiveCamera(50, canvas.width / canvas.height, 2, 10000);
camera.position.set(0, 10, -25);
camera.updateProjectionMatrix();
camera.lookAt(0, 0, 0);
scene.add(camera);
window.requestAnimationFrame(_loop);
function _loop(time) {
ImGui_Impl.NewFrame(time);
ImGui.NewFrame();
ImGui.SetNextWindowPos(new ImGui.ImVec2(20, 20), ImGui.Cond.FirstUseEver);
ImGui.SetNextWindowSize(new ImGui.ImVec2(294, 140), ImGui.Cond.FirstUseEver);
ImGui.Begin("Visblility Toggles:");
ImGui.Checkbox("box_1 (near)", (value = box_1_mesh.visible) => box_1_mesh.visible = value);
ImGui.Checkbox("box_2 (distant)", (value = box_2_mesh.visible) => box_2_mesh.visible = value);
ImGui.Checkbox("grid", (value = grid.visible) => grid.visible = value);
ImGui.Checkbox("subgrid", (value = subgrid.visible) => subgrid.visible = value);
ImGui.End();
ImGui.EndFrame();
ImGui.Render();
renderer.setClearColor(new THREE.Color(clear_color.x, clear_color.y, clear_color.z), clear_color.w);
renderer.setSize(canvas.width, canvas.height);
camera.aspect = canvas.width / canvas.height;
camera.updateProjectionMatrix();
renderer.render(scene, camera);
ImGui_Impl.RenderDrawData(ImGui.GetDrawData());
renderer.state.reset();
window.requestAnimationFrame(_loop);
}
})();
#output {
position: absolute;
top: 0px;
right: 0px;
width: 100%;
height: 100%;
z-index: 1;
}
<script>
// emu localStorage otherwise ImGUI fails because S.O blocks localStorage
{
const localStorageStorage = new Map();
const localStorage = {
getItem(k) { return localStorageStorage.get(k); },
setItem(k,v) { return localStorageStorage.set(k, v); },
};
Object.defineProperty(window, 'localStorage', {
get() { return localStorage; }
});
}
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r125/three.min.js"></script>
<script src="https://flyover.github.io/imgui-js/dist/imgui.umd.js"></script>
<script src="https://flyover.github.io/imgui-js/dist/imgui_impl.umd.js"></script>
<script src="https://flyover.github.io/nanovg-js/dist/nanovg.umd.js"></script>
<canvas tabindex="0" id="output"></canvas>
Is there anything wrong with my setup of imgui-js or three-js? Any ideas as to what I might do so that the ImGui_Impl.RenderDrawData call does not impact the rendering of my three.js scene?

The issue is imgui-js is trashing the attribute state.
You might want to consider running imgui-js in another canvas overlayed on top of the
three.js canvas, each with their own WebGL context. Then they don't have to worry about each other.
A quick hack is this
const gl = renderer.getContext();
window.vao = window.vao || gl.createVertexArray();
const oldVao = gl.getParameter(gl.VERTEX_ARRAY_BINDING);
gl.bindVertexArray(vao);
ImGui_Impl.RenderDrawData(ImGui.GetDrawData());
gl.bindVertexArray(oldVao);
But that hack only works in WebGL2. To fully save and restore the missing state is not hard but handling WebGL1, and extensions, and WebGL2 is probably 50-80 lines of code.
I filed an issue here with an example PR
(async function() {
await ImGui.default();
const canvas = document.getElementById("output");
const devicePixelRatio = window.devicePixelRatio || 1;
canvas.width = canvas.scrollWidth * devicePixelRatio;
canvas.height = canvas.scrollHeight * devicePixelRatio;
window.addEventListener("resize", () => {
const devicePixelRatio = window.devicePixelRatio || 1;
canvas.width = canvas.scrollWidth * devicePixelRatio;
canvas.height = canvas.scrollHeight * devicePixelRatio;
});
ImGui.CreateContext();
ImGui_Impl.Init(canvas);
ImGui.StyleColorsDark();
const clear_color = new ImGui.ImVec4(0.3, 0.3, 0.3, 1.00);
const renderer = new THREE.WebGLRenderer({ canvas: canvas });
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.gammaFactor = 2.2;
renderer.physicallyCorrectLights = true;
renderer.outputEncoding = THREE.sRGBEncoding;
const scene = new THREE.Scene();
let floorDim = 1000;
var grid = new THREE.GridHelper(floorDim, 200, 'orange', 'white');
grid.name = "grid";
grid.material.opacity = 1.0;
grid.material.transparent = true;
grid.material.color.convertGammaToLinear(2.2);
grid.position.set(0, 2, 0);
scene.add(grid);
var subgrid = new THREE.GridHelper(floorDim, 600, 'grey', 'grey');
subgrid.name = "subgrid";
subgrid.material.opacity = 1.0;
subgrid.material.color.convertGammaToLinear(2.2);
subgrid.material.transparent = true;
subgrid.position.set(0, 1, 0);
scene.add(subgrid);
const light = new THREE.DirectionalLight(0xffffff, 0.8);
light.position.set(0, 100, -50);
light.lookAt(new THREE.Vector3(0, 0, 0));
scene.add(light);
const box_1_mesh = new THREE.Mesh(new THREE.BoxGeometry(5, 5, 5), new THREE.MeshLambertMaterial({ color:0x970000 }));
box_1_mesh.position.set(0, 5, 0);
scene.add(box_1_mesh);
const box_2_mesh = new THREE.Mesh(new THREE.BoxGeometry(5, 5, 5), new THREE.MeshLambertMaterial({ color:0x333000 }));
box_2_mesh.position.set(-2, 6, 7);
scene.add(box_2_mesh);
const camera = new THREE.PerspectiveCamera(50, canvas.width / canvas.height, 2, 10000);
camera.position.set(0, 10, -25);
camera.updateProjectionMatrix();
camera.lookAt(0, 0, 0);
scene.add(camera);
setTimeout(() => {
grid.visible = false;
}, 1000);
setTimeout(() => {
grid.visible = true;
}, 2000);
setTimeout(() => {
console.log(grid.visible);
}, 2500);
window.requestAnimationFrame(_loop);
function _loop(time) {
ImGui_Impl.NewFrame(time);
ImGui.NewFrame();
ImGui.SetNextWindowPos(new ImGui.ImVec2(20, 20), ImGui.Cond.FirstUseEver);
ImGui.SetNextWindowSize(new ImGui.ImVec2(294, 140), ImGui.Cond.FirstUseEver);
ImGui.Begin("Visblility Toggles:");
ImGui.Checkbox("box_1 (near)", (value = box_1_mesh.visible) => box_1_mesh.visible = value);
ImGui.Checkbox("box_2 (distant)", (value = box_2_mesh.visible) => box_2_mesh.visible = value);
ImGui.Checkbox("grid", (value = grid.visible) => grid.visible = value);
ImGui.Checkbox("subgrid", (value = subgrid.visible) => subgrid.visible = value);
ImGui.End();
ImGui.EndFrame();
ImGui.Render();
renderer.setClearColor(new THREE.Color(clear_color.x, clear_color.y, clear_color.z), clear_color.w);
renderer.setSize(canvas.width, canvas.height);
camera.aspect = canvas.width / canvas.height;
camera.updateProjectionMatrix();
renderer.render(scene, camera);
const gl = renderer.getContext();
window.vao = window.vao || gl.createVertexArray();
const oldVao = gl.getParameter(gl.VERTEX_ARRAY_BINDING);
gl.bindVertexArray(vao);
ImGui_Impl.RenderDrawData(ImGui.GetDrawData());
gl.bindVertexArray(oldVao);
renderer.state.reset();
window.requestAnimationFrame(_loop);
}
})();
#output {
position: absolute;
top: 0px;
right: 0px;
width: 100%;
height: 100%;
z-index: 1;
}
<script>
// emu localStorage otherwise ImGUI fails because S.O blocks localStorage
{
const localStorageStorage = new Map();
const localStorage = {
getItem(k) { return localStorageStorage.get(k); },
setItem(k,v) { return localStorageStorage.set(k, v); },
};
Object.defineProperty(window, 'localStorage', {
get() { return localStorage; }
});
}
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r125/three.js"></script>
<script src="https://flyover.github.io/imgui-js/dist/imgui.umd.js"></script>
<script src="https://flyover.github.io/imgui-js/dist/imgui_impl.umd.js"></script>
<script src="https://flyover.github.io/nanovg-js/dist/nanovg.umd.js"></script>
<canvas tabindex="0" id="output"></canvas>

Related

How to resize threejs mesh via controls

The only way I know how to resize an extruded path is but reconstructing it. I want to know whether there is a way I can control the length/width/height in the threejs controls.
Here is my code:
'use strict';
/* global THREE, dat */
function main() {
const canvas = document.querySelector('#canvas');
const renderer = new THREE.WebGLRenderer({canvas});
const fov = 45;
const aspect = 2; // the canvas default
const near = 0.1;
const far = 100;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.set(0, 10, 20);
const controls = new THREE.OrbitControls(camera, canvas);
controls.target.set(0, 5, 0);
controls.update();
const scene = new THREE.Scene();
scene.background = new THREE.Color('black');
{
const planeSize = 40;
const loader = new THREE.TextureLoader();
const texture = loader.load('https://r105.threejsfundamentals.org/threejs/resources/images/checker.png');
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.magFilter = THREE.NearestFilter;
const repeats = planeSize / 2;
texture.repeat.set(repeats, repeats);
const planeGeo = new THREE.PlaneBufferGeometry(planeSize, planeSize);
const planeMat = new THREE.MeshPhongMaterial({
map: texture,
side: THREE.DoubleSide,
});
const mesh = new THREE.Mesh(planeGeo, planeMat);
mesh.rotation.x = Math.PI * -.5;
scene.add(mesh);
}
{
// Create a Shape Mesh with basic material
const shape = new THREE.Shape();
const x_len = 12;
const y_len = 8;
const z_len = 1;
shape.moveTo( 0, 0 );
shape.lineTo( 0, y_len );
shape.lineTo( x_len, y_len );
shape.lineTo( x_len, 0 );
shape.lineTo( 0, 0 );
const thickness = 0.5;
shape.lineTo( thickness, thickness );
shape.lineTo( x_len-thickness, thickness );
shape.lineTo( x_len-thickness, y_len-thickness );
shape.lineTo( thickness, y_len-thickness );
shape.lineTo( thickness, thickness );
const extrudeSettings = {
steps: 2,
depth: z_len,
bevelEnabled: false,
bevelThickness: 1,
bevelSize: 1,
bevelOffset: 0,
bevelSegments: 1
};
const geometry = new THREE.ExtrudeGeometry( shape, extrudeSettings );
const material = new THREE.MeshPhongMaterial({color: '#CA8'});
const mesh = new THREE.Mesh( geometry, material ) ;
scene.add( mesh );
}
class ColorGUIHelper {
constructor(object, prop) {
this.object = object;
this.prop = prop;
}
get value() {
return `#${this.object[this.prop].getHexString()}`;
}
set value(hexString) {
this.object[this.prop].set(hexString);
}
}
function makeXYZGUI(gui, vector3, name, onChangeFn) {
const folder = gui.addFolder(name);
folder.add(vector3, 'x', -10, 10).onChange(onChangeFn);
folder.add(vector3, 'y', 0, 10).onChange(onChangeFn);
folder.add(vector3, 'z', -10, 10).onChange(onChangeFn);
folder.open();
}
{
const color = 0xFFFFFF;
const intensity = 1;
const light = new THREE.PointLight(color, intensity);
light.position.set(0, 10, 4);
scene.add(light);
const helper = new THREE.PointLightHelper(light);
scene.add(helper);
function updateLight() {
helper.update();
}
const gui = new dat.GUI();
gui.addColor(new ColorGUIHelper(light, 'color'), 'value').name('color');
gui.add(light, 'intensity', 0, 2, 0.01);
gui.add(light, 'distance', 0, 40).onChange(updateLight);
makeXYZGUI(gui, light.position, 'position');
}
function resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
function render() {
if (resizeRendererToDisplaySize(renderer)) {
const canvas = renderer.domElement;
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
renderer.render(scene, camera);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
main();
<html lang="en">
<head>
<meta charset="UTF-8" />
<!-- Simple reset to delete the margins -->
<style>
body { margin: 0; }
canvas { width: 100%; height: 100% }
</style>
</head>
<body>
<!-- Our code -->
<canvas id="canvas"></canvas>
<script src="https://r105.threejsfundamentals.org/threejs/resources/threejs/r105/three.min.js"></script>
<script src="https://r105.threejsfundamentals.org/threejs/resources/threejs/r105/js/controls/OrbitControls.js"></script>
<script src="https://r105.threejsfundamentals.org/threejs/../3rdparty/dat.gui.min.js"></script>
</html>
In this code, I want to change x_len, y_len, z_len
I'm using a library called dat.gui.
The problem is that each of these values map to multiple properties. For example, x_len maps to
shape.curves[2].x
shape.curves[3].x
shape.curves[6].x
shape.curves[7].x
so I probably need something like:
gui.add(some object to point to all relevant curves, 'x', 0, 40).onChange(someCallback);
any help will be appreciated.

Three.js all texture are white

I've changed the version of my three.js because i wanted to use projector but now all my texture went white. I can't find what is wrong with it. I'm not getting any error in the console, which makes me a bit lost.
I was using r122.
Any body know what is happening ?
most of the code here comes from a code pen :
https://codepen.io/yitliu/pen/bJoQLw
//----------VARIABLES----------
const dpi = window.devicePixelRatio;
const theCanvas = document.getElementById('canvas');
var h = window.innerHeight,
w = window.innerWidth;
aspectRatio = w / h,
fieldOfView = 25,
nearPlane = .1,
farPlane = 1000;
container = document.getElementById('container');
var dae, scene, camera, renderer;
var Colors = {
cyan: 0x248079,
brown: 0xA98F78,
brownDark: 0x9A6169,
green: 0x65BB61,
greenLight: 0xABD66A,
blue: 0x6BC6FF
};
function init() {
//----------SCENE----------
scene = new THREE.Scene();
//----------CAMERA----------
camera = new THREE.PerspectiveCamera(
fieldOfView,
aspectRatio,
nearPlane,
farPlane);
//----------RENDER----------
renderer = new THREE.WebGLRenderer({ canvas: canvas, alpha: true, antialias: true });
renderer.setSize(w * dpi, h * dpi);
theCanvas.style.width = `${w}px`;
theCanvas.style.height = `${h}px`;
renderer.shadowMapEnabled = true;
renderer.shadowMapType = THREE.PCFSoftShadowMap;
document.body.appendChild(renderer.domElement);
camera.position.set(-5, 6, 8);
camera.lookAt(new THREE.Vector3(0, 0, 0));
//---------LIGHT---------
var light = new THREE.AmbientLight(0xffffff, .5);
var shadowLight = new THREE.DirectionalLight(0xffffff, .5);
shadowLight.position.set(200, 200, 200);
shadowLight.castShadow = true;
var backLight = new THREE.DirectionalLight(0xffffff, .2);
backLight.position.set(-100, 200, 50);
backLight.castShadow = true;
scene.add(backLight);
scene.add(light);
scene.add(shadowLight);
//---------CONTROLS---------
const controls = new THREE.OrbitControls(camera, renderer.domElement);
//---------GEOMETRY---------
var geometry_left = new THREE.CubeGeometry(2, .2, 4);
var material_grass = new THREE.MeshLambertMaterial({ color: Colors.greenLight });
var ground_left = new THREE.Mesh(geometry_left, material_grass);
ground_left.position.set(-1, 0.1, 0);
ground_left.receiveShadow = true;
scene.add(ground_left);
var geometry_bot = new THREE.CubeGeometry(4, .2, 1);
var material_grass = new THREE.MeshLambertMaterial({ color: Colors.greenLight });
var ground_bot = new THREE.Mesh(geometry_bot, material_grass);
ground_bot.position.set(0, 0.1, 2);
ground_bot.receiveShadow = true;
scene.add(ground_bot);
var geometry_top = new THREE.CubeGeometry(4, .2, 1);
var material_grass = new THREE.MeshLambertMaterial({ color: Colors.greenLight });
var ground_top = new THREE.Mesh(geometry_top, material_grass);
ground_top.position.set(0, 0.1, -2);
ground_top.receiveShadow = true;
scene.add(ground_top);
var geometry_river = new THREE.CubeGeometry(1, .1, 4);
var material_river = new THREE.MeshLambertMaterial({ color: Colors.blue });
var river = new THREE.Mesh(geometry_river, material_river);
river.position.set(.5, .1, 0);
river.receiveShadow = true;
scene.add(river);
var geometry_bed = new THREE.CubeGeometry(1, .05, 4);
var bed = new THREE.Mesh(geometry_bed, material_grass);
bed.position.set(.5, .025, 0);
scene.add(bed);
var geometry_right = new THREE.CubeGeometry(1, .2, 4);
var ground_right = new THREE.Mesh(geometry_right, material_grass);
ground_right.position.set(1.5, 0.1, 0);
ground_right.receiveShadow = true;
scene.add(ground_right);
var tree = function (x, z) {
this.x = x;
this.z = z;
var material_trunk = new THREE.MeshLambertMaterial({ color: Colors.brownDark });
var geometry_trunk = new THREE.CubeGeometry(.15, .15, .15);
var trunk = new THREE.Mesh(geometry_trunk, material_trunk);
trunk.position.set(this.x, .275, this.z);
trunk.castShadow = true;
trunk.receiveShadow = true;
scene.add(trunk);
var geometry_leaves = new THREE.CubeGeometry(.25, .4, .25);
var material_leaves = new THREE.MeshLambertMaterial({ color: Colors.green });
var leaves = new THREE.Mesh(geometry_leaves, material_leaves);
leaves.position.set(this.x, .2 + .15 + .4 / 2, this.z);
leaves.castShadow = true;
scene.add(leaves);
}
tree(-1.5, -1.5);
//tree(-1.25,.75);
tree(-.25, -.85);
tree(0.4, 2);
//tree(1.25,-2);
tree(1.75, .35);
var material_wood = new THREE.MeshLambertMaterial({ color: Colors.brown });
var geometry_block = new THREE.CubeGeometry(1.3, .02, .6);
var block = new THREE.Mesh(geometry_block, material_wood);
block.position.set(.5, .21, .2);
block.castShadow = true;
block.receiveShadow = true;
scene.add(block);
//---------CAR---------
var loader = new THREE.ColladaLoader();
loader.load('offroadcar.dae', function (collada) {
dae = collada.scene;
dae.scale.x = dae.scale.y = dae.scale.z = 0.1;
dae.position.set(-1, .2, 0);
dae.updateMatrix();
//customizeShadow(dae, .25)
scene.add(dae);
dae.castShadow = true;
dae.receiveShadow = true;
})
}// end of init
//---------STARTING---------
init();
animate();
//---------LISTENERS---------
theCanvas.addEventListener('click', function (evt) {
clickInfo.userHasClicked = true;
clickInfo.x = evt.clientX - theCanvas.offsetLeft;
clickInfo.y = evt.clientY - theCanvas.offsetTop;
}, false);
//---------METHODS---------
function animate() {
renderer.render(scene, camera);
requestAnimationFrame(function () { animate(); });
}

Three js enabling shadow render slow

I am loading a building model to the scene using GLTFLoader and apply some texture, also Adding two PointLight source with shadow enabled. I am using self shadow for the building, that is the building itself should create shadow from light source.
But when I load the page, I am having some performance issue withe page, the frame rate is too slow on status and entire system behave hang.
But if disable the shadow everything work as expected. Is this expected or I can improve it on coding.
Here is the working fiddle
http://jsfiddle.net/n9eg3kox/
var camera, scene, renderer, stats;
var mesh;
var controls;
var BuildingObj;
var OutFloor;
var enableShadow = true; // if I make it false the code work fine
var pointLight2, pointLight3;
function init() {
var webglEl = document.getElementById('webgl');
if (!Detector.webgl) {
Detector.addGetWebGLMessage(webglEl);
alert("WebGL no Support");
return;
}
THREE.ImageUtils.crossOrigin = '';
renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
renderer.setPixelRatio(window.devicePixelRatio * 1.5);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.physicallyCorrectLights = true;
renderer.gammaInput = true;
renderer.gammaOutput = true;
renderer.shadowMap.enabled = enableShadow;
renderer.toneMapping = THREE.ReinhardToneMapping;
webglEl.appendChild(renderer.domElement);
renderer.setClearColor(0x555555, 1);
var width = window.innerWidth, height = window.innerHeight;
camera = new THREE.PerspectiveCamera(45, width / height, 0.01, 2000);
camera.position.x = 0;
camera.position.y = 4;
camera.position.z = 30;
scene = new THREE.Scene();
var axesHelper = new THREE.AxesHelper(100);
scene.add(axesHelper);
var intensity = 5;
var distance = 40;
var decay = 1.0;
pointLight2 = new THREE.PointLight(0xFFFFFF, intensity);
pointLight2.add(new THREE.Mesh(new THREE.SphereBufferGeometry(3, 16, 16), new THREE.MeshPhongMaterial({ color: 0xfffdfb, emissive: 0xfffdfb, emissiveIntensity: 100 })));
pointLight2.position.set(-60, 80, 40);
pointLight2.castShadow = enableShadow;
pointLight2.visible = true;
pointLight2.shadow.mapSize.width = 1024;
pointLight2.shadow.mapSize.height = 1024;
scene.add(pointLight2);
pointLight3 = new THREE.PointLight(0xFFFFFF, intensity);
pointLight3.add(new THREE.Mesh(new THREE.SphereBufferGeometry(3, 16, 16), new THREE.MeshPhongMaterial({ color: 0xfffdfb, emissive: 0xfffdfb, emissiveIntensity: 100 })));
pointLight3.position.set(60, 80, 40);
pointLight3.castShadow = enableShadow;
pointLight3.shadow.mapSize.width = 1024;
pointLight3.shadow.mapSize.height = 1024;
pointLight3.visible = true;
scene.add(pointLight3);
//var light = new THREE.HemisphereLight( 0xffffbb, 0x080820, 21 );
//scene.add( light );
controls = new THREE.OrbitControls(camera, webglEl);
stats = new Stats();
webglEl.appendChild(stats.dom);
loadObject();
animate();
}
function animate() {
controls.update();
stats.update();
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
function loadObject() {
var loader = new THREE.GLTFLoader();
loader.load(
//'./Model/GLTF/test.glb',
'./test/test.glb',
function (gltf) {
gltf.scene.traverse(function (node) {
if (node.isGroup) {
if (node.name === "Building") {
BuildingObj = node;
} else if (node.name === "Cube") {
OutFloor = node;
}
}
});
scene.add(OutFloor);
scene.add(BuildingObj);
applyMaterialToObject();
},
function (xhr) {
console.log((xhr.loaded / xhr.total * 100) + '% loaded');
},
function (error) {
console.log('An error happened---' + error);
}
);
}
function applyMaterialToObject(object) {
for (var i = 0; i < BuildingObj.children.length; i++) {
var obj = BuildingObj.children[i];
var material = new THREE.MeshStandardMaterial({ roughness: 0.8, metalness: 0.3, bumpScale: - 0.05, color: 0xffffff, });
loadTexturesToMaterial(BuildingObj.children[i], material, "./test/brick.jpg", "./test/brick_b.jpg", "./test/brick_r.jpg", 25, 70, Math.PI / 2);
}
for (var i = 0; i < OutFloor.children.length; i++) {
var obj = OutFloor.children[i];
var material = new THREE.MeshStandardMaterial({ roughness: 0.5, metalness: 0.8, bumpScale: - 0.05, color: 0xffffff });
loadTexturesToMaterial(obj, material, "./test/tile2.jpg", "./test/tile2_b.jpg", "./test/tile2_r.jpg", 35, 100, Math.PI / 2);
}
}
function loadTexturesToMaterial(obj, material, map_img, bumpMap_img, roughnessMap_img, v_count, h_count, rotation) {
obj.receiveShadow = enableShadow;
obj.castShadow = enableShadow;
obj.material = material;
obj.material.side = THREE.DoubleSide;
var textureLoader = new THREE.TextureLoader();
textureLoader.load(map_img, function (map) {
map.wrapS = THREE.RepeatWrapping;
map.wrapT = THREE.RepeatWrapping;
map.rotation = rotation;
map.repeat.set(v_count, h_count);
obj.material.map = map;
obj.material.needsUpdate = true;
});
textureLoader.load(bumpMap_img, function (map) {
map.wrapS = THREE.RepeatWrapping;
map.wrapT = THREE.RepeatWrapping;
map.rotation = rotation;
map.repeat.set(v_count, h_count);
obj.material.bumpMap = map;
obj.material.needsUpdate = true;
});
textureLoader.load(roughnessMap_img, function (map) {
map.wrapS = THREE.RepeatWrapping;
map.wrapT = THREE.RepeatWrapping;
map.rotation = rotation;
map.repeat.set(v_count, h_count);
obj.material.roughnessMap = map;
obj.material.needsUpdate = true;
});
}
Note: I have created the model using blender.
Edit: Texture and model link
https://github.com/SourceCodeZone/3D

Three.js. Why does this RGBA texture not change the associated material opacity?

In three.js I create a material that uses a texture to control transparency. The texture is created from a canvas. The canvas is drawn with fillStyle of rgba. Alpha varies across the canvas. The effect I am after is to vary transparency across the object the material is attached to. That is not happening. The object remains opaque.
Code:
tubeTexture = new THREE.Texture(canvas);
tubeTexture.center.set(0.5, 0.5);
tubeTexture.rotation = Math.PI/2.0;
// turn off any filtering to create sharp edges when highlighting
// tube section based on colorRamp highlighting.
tubeTexture.minFilter = tubeTexture.magFilter = THREE.NearestFilter;
// let tubeMaterial = new THREE.MeshBasicMaterial({ map: tubeTexture });
let tubeMaterial = new THREE.MeshPhongMaterial({ map: tubeTexture });
tubeMaterial.side = THREE.DoubleSide;
tubeMaterial.transparent = true;
// let tubeMaterial = sceneManager.stickMaterial.clone();
const tubeMesh = new THREE.Mesh(tubeGeometry, tubeMaterial);
What am I missing?
It seems to work for me
'use strict';
/* global THREE */
function main() {
const canvas = document.querySelector('#c');
const renderer = new THREE.WebGLRenderer({
canvas: canvas
});
const fov = 75;
const aspect = 2; // the canvas default
const near = 0.1;
const far = 5;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.z = 2;
const scene = new THREE.Scene();
scene.background = new THREE.Color('white');
{
const color = 0xFFFFFF;
const intensity = 1;
const light = new THREE.DirectionalLight(color, intensity);
light.position.set(-1, 2, 4);
scene.add(light);
}
const boxWidth = 1;
const boxHeight = 1;
const boxDepth = 1;
const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
const ctx = document.createElement('canvas').getContext('2d');
ctx.canvas.width = 256;
ctx.canvas.height = 256;
ctx.fillStyle = 'rgba(255, 255, 255, 0.25)';
ctx.beginPath();
ctx.arc(128, 128, 120, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = 'rgba(255, 255, 255, 0.5)';
ctx.beginPath();
ctx.arc(128, 128, 64, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = 'rgba(255, 255, 255, 1.0)';
ctx.beginPath();
ctx.arc(128, 128, 32, 0, Math.PI * 2);
ctx.fill();
const texture = new THREE.CanvasTexture(ctx.canvas);
const root = new THREE.Object3D();
scene.add(root);
function makeInstance(geometry, color, x) {
const material = new THREE.MeshPhongMaterial({
color,
map: texture,
transparent: true,
side: THREE.DoubleSide,
alphaTest: 0.1,
});
const cube = new THREE.Mesh(geometry, material);
root.add(cube);
cube.position.x = x;
return cube;
}
const cubes = [
makeInstance(geometry, 0x44aa88, 0),
makeInstance(geometry, 0x8844aa, -2),
makeInstance(geometry, 0xaa8844, 2),
];
function resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
function render(time) {
time *= 0.001;
if (resizeRendererToDisplaySize(renderer)) {
const canvas = renderer.domElement;
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
root.rotation.y = time * .2;
cubes.forEach((cube, ndx) => {
const speed = 1 + ndx * .1;
const rot = time * speed;
cube.rotation.x = rot;
cube.rotation.y = rot;
});
renderer.render(scene, camera);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
main();
body {
margin: 0;
}
#c {
width: 100vw;
height: 100vh;
display: block;
}
<canvas id="c"></canvas>
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r103/three.min.js"></script>
Of course there are the normal issues related to transparency and sorting. An object will not be consistantly transparent to itself, only to other objects.

Two objects don't cast a shadow while other one does

I have exactly the same three cube objects except their x position.
I want them to cast a shadow, but somehow two of them don't cast a shadow while the other one does.
Here is the pic of what's happening.
https://ibb.co/z6Vwxmf
I'm sure that castShadow is set to true on all the objects.
And I don't think I missed any shadow setting property either (because the middle object casts a shadow properly.)
These objects are created under //left cube //right cube comments in the below code.
< script >
window.addEventListener('load', init, false);
function init(event) {
createScene();
createLights();
createTile01();
createTile02();
createTile03();
createBase();
loop();
}
var scene, camera, Width, Height, renderer, container;
function createScene() {
Width = window.innerWidth;
Height = window.innerHeight;
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.x = 0;
camera.position.y = 10;
camera.position.z = 50;
camera.lookAt(scene.position);
renderer = new THREE.WebGLRenderer();
renderer.setClearColor(new THREE.Color(0x000000));
renderer.setSize(Width, Height);
renderer.shadowMap.enabled = true;
container = document.getElementById('scene');
container.appendChild(renderer.domElement);
window.addEventListener('resize', handleWindowResize, false);
}
function handleWindowResize() {
Height = window.InnerHeight;
Width = window.InnerWidth;
renderer.setSize(Width, Height);
camera.aspect = Width / Height;
camera.updateProjectionMatrix();
}
var ambiLight, spotLight;
function createLights() {
ambiLight = new THREE.AmbientLight(0xffffff);
scene.add(ambiLight);
spotLight = new THREE.DirectionalLight(0xffffff);
spotLight.position.set(0, 30, -0);
spotLight.intensity = 1;
spotLight.castShadow = true;
scene.add(spotLight);
}
Tile01 = function() {
var geom = new THREE.BoxGeometry(10, 10, 2);
var mat = new THREE.MeshPhongMaterial({
color: 0x53b0df
});
this.mesh = new THREE.Mesh(geom, mat);
this.mesh.receiveShadow = true;
this.mesh.castShadow = true;
}
var tile01;
function createTile01() {
tile01 = new Tile01();
tile01.mesh.position.set(0, 0, 0);
scene.add(tile01.mesh);
}
//right cube
Tile02 = function() {
var geom = new THREE.BoxGeometry(10, 10, 2);
var mat = new THREE.MeshPhongMaterial({
color: 0x25b0cf
});
this.mesh = new THREE.Mesh(geom, mat);
this.mesh.receiveShadow = true;
this.mesh.castShadow = true;
}
var tile02;
function createTile02() {
tile02 = new Tile02();
tile02.mesh.position.set(20, 0, 0);
scene.add(tile02.mesh);
}
//left cube
Tile03 = function() {
var geom = new THREE.BoxGeometry(10, 10, 2);
var mat = new THREE.MeshPhongMaterial({
color: 0x00b0df
});
this.mesh = new THREE.Mesh(geom, mat);
this.mesh.receiveShadow = true;
this.mesh.castShadow = true;
}
var tile03;
function createTile03() {
tile03 = new Tile03();
tile03.mesh.position.set(-20, 0, 0);
scene.add(tile03.mesh);
}
Base = function() {
var geom = new THREE.CylinderGeometry(100, 30, 5, 60);
var mat = new THREE.MeshPhongMaterial({
color: 0xcf34ec
});
this.mesh = new THREE.Mesh(geom, mat);
this.mesh.castShadow = true;
this.mesh.receiveShadow = true;
}
var base;
function createBase() {
base = new Base();
base.mesh.position.set(0, -10, -20);
scene.add(base.mesh);
}
function loop() {
renderer.render(scene, camera);
requestAnimationFrame(loop);
}
< /script>
Could you help me figure out what's wrong with the setting?
I was able to resolve the issue myself.
Referring to some solutions I found at other Q/As about a shadow issue, I added a shadow.camera.left/right/top/bottom properties to the light and it worked.
The below is the code I corrected.
Now I can see the shadows of all the three objects.
var ambiLight, spotLight;
function createLights() {
ambiLight = new THREE.AmbientLight(0xffffff);
scene.add(ambiLight);
spotLight = new THREE.DirectionalLight(0xffffff);
spotLight.position.set(0, 30, -0);
spotLight.intensity = 1;
spotLight.castShadow = true;
spotLight.shadow.camera.left = -400;
spotLight.shadow.camera.right = 400;
spotLight.shadow.camera.top = 400;
spotLight.shadow.camera.bottom = -400;
spotLight.shadow.camera.near = 1;
spotLight.shadow.camera.far = 1000;
spotLight.shadow.mapSize.width = 2048;
spotLight.shadow.mapSize.height = 2048;
scene.add(spotLight);
}

Resources