Undefined Error when applying materials to gltf object - three.js

I created a Three.js Scene where it loads a GLtf Object (.glb) inside a RGBELoader (for hdr Enviroment Texture Lighting )
I then give each Mesh inside this GLtf Object a new Material. Like this:
gltfObject.traverse((ChildGLTF) => {
ChildGLTF.children[0].material = MidMaterial;
ChildGLTF.children[1].material = TopMaterial;
ChildGLTF.children[2].material = BotMaterial;
});
Now the strange thing is, I get an Error and at the same time the materials are applied like I want them to. So it actually works.
Still I want to get rid of that error or at least understand what is causing it.
Thats the Error:
script.js:77 Uncaught (in promise) TypeError: Cannot set properties of undefined (setting 'material')
at script.js:77
at Mesh.traverse (three.module.js:6907)
at Group.traverse (three.module.js:6913)
at script.js:72
at GLTFLoader.js:175
at GLTFLoader.js:1989
So my best guess is, that there are more than one .material Attributes? But how can i specify, that I only want the material that is changeable..
Or is it, that 'gltfObject.traverse((ChildGLTF)' runs more than one time with ChildGLTF as an array? If so, "console.log( ChildGLTF[0] );" gives "undefined" ..
Here are the console logs
console.log( ChildGLTF[0] ); //'undefined'
console.log( ChildGLTF.children[0] ); //works fine
console.log( ChildGLTF.children[0].material ); //'Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'material')'
console.log( ChildGLTF.children[0] )
! Mesh {uuid: '3BE5076C-A90D-47B4-BE40-D1E77E4F4DEC', name: 'Cube', type: 'Mesh', parent: Group, children: Array(0), …}
animations: []
castShadow: false
children: []
frustumCulled: true
geometry: BufferGeometry {uuid: 'EC8A35A7-1942-4556-9D93-6C3E25F4C77A', name: '', type: 'BufferGeometry', index: BufferAttribute, attributes: {…}, …}
layers: Layers {mask: 1}
material: MeshStandardMaterial {uuid: 'ACA40D34-B763-42DA-A956-3ABBAC901D37', name: '', type: 'MeshStandardMaterial', fog: true, blending: 1, …}
matrix: Matrix4 {elements: Array(16)}
matrixAutoUpdate: true
matrixWorld: Matrix4 {elements: Array(16)}
matrixWorldNeedsUpdate: false
name: "Cube"
parent: Group {uuid: '27EE9C8E-3B31-4483-8058-CA2DA42070FC', name: 'Scene', type: 'Group', parent: Scene, children: Array(3), …}
position: Vector3 {x: 0, y: 0, z: 0}
quaternion: Quaternion {_x: 0, _y: 0, _z: 0, _w: 1, _onChangeCallback: ƒ}
receiveShadow: false
renderOrder: 0
rotation: Euler {_x: 0, _y: 0, _z: 0, _order: 'XYZ', _onChangeCallback: ƒ}
scale: Vector3 {x: 1, y: 1, z: 1}
type: "Mesh"
up: Vector3 {x: 0, y: 1, z: 0}
userData: {name: 'Cube'}
uuid: "3BE5076C-A90D-47B4-BE40-D1E77E4F4DEC"
visible: true
drawMode: (...)
eulerOrder: (...)
id: 40
modelViewMatrix: Matrix4 {elements: Array(16)}
normalMatrix: Matrix3 {elements: Array(9)}
useQuaternion: (...)
[[Prototype]]: Object3D
console.log( ChildGLTF.children[0].material );
! MeshStandardMaterial {uuid: 'FBA72EAB-93C3-4F92-B141-1BA011BB81FD', name: 'CubeMaterial', type: 'MeshStandardMaterial', fog: true, blending: 1, …}
alphaMap: null
alphaTest: 0
aoMap: null
aoMapIntensity: 1
blendDst: 205
blendDstAlpha: null
blendEquation: 100
blendEquationAlpha: null
blendSrc: 204
blendSrcAlpha: null
blending: 1
bumpMap: null
bumpScale: 1
clipIntersection: false
clipShadows: false
clippingPlanes: null
color: Color {r: 0.011123105883598328, g: 0.004119289573282003, b: 0.8000000715255737}
colorWrite: true
defines: {STANDARD: ''}
depthFunc: 3
depthTest: true
depthWrite: true
displacementBias: 0
displacementMap: null
displacementScale: 1
dithering: false
emissive: Color {r: 0, g: 0, b: 0}
emissiveIntensity: 1
emissiveMap: null
envMap: null
envMapIntensity: 1
flatShading: false
fog: true
lightMap: null
lightMapIntensity: 1
map: null
metalness: 0
metalnessMap: null
morphNormals: false
morphTargets: false
name: "CubeMaterial"
normalMap: null
normalMapType: 0
normalScale: Vector2 {x: 1, y: 1}
opacity: 1
polygonOffset: false
polygonOffsetFactor: 0
polygonOffsetUnits: 0
precision: null
premultipliedAlpha: false
refractionRatio: 0.98
roughness: 0.5
roughnessMap: null
shadowSide: null
side: 2
skinning: false
stencilFail: 7680
stencilFunc: 519
stencilFuncMask: 255
stencilRef: 0
stencilWrite: false
stencilWriteMask: 255
stencilZFail: 7680
stencilZPass: 7680
toneMapped: true
transparent: false
type: "MeshStandardMaterial"
userData: {}
uuid: "FBA72EAB-93C3-4F92-B141-1BA011BB81FD"
version: 0
vertexColors: false
vertexTangents: false
visible: true
wireframe: false
wireframeLinecap: "round"
wireframeLinejoin: "round"
wireframeLinewidth: 1
id: 7
overdraw: (...)
shading: (...)
stencilMask: (...)
wrapAround: (...)
wrapRGB: (...)
[[Prototype]]: Material

.traverse(...) is going to run that callback for every object within the model, and your code assumes each object has exactly three children. That's not possible, because the model would have to be infinitely deep, and when you eventually reach an object that doesn't have children, doing .children[0].material will throw these errors.
You'll want to check what ChildGLTFis, and only modify that one object during the loop.
gltfObject.traverse((child) => {
if (!child.isMesh) return;
if (child.name === 'MyMidMeshName') { // change this name
child.material = MidMaterial;
} else if (child.name === 'MyTopMeshName') { // change this name
// ...
} else {
// ...
}
});

Related

Why is the intersection distance the same of all objects, even though they have different positions?

We have three spheres
const object1 = new THREE.Mesh(
new THREE.SphereGeometry(0.5, 16, 16),
new THREE.MeshBasicMaterial({ color: '#ff0000' })
)
object1.position.x = - 2
const object2 = new THREE.Mesh(
new THREE.SphereGeometry(0.5, 16, 16),
new THREE.MeshBasicMaterial({ color: '#ff0000' })
)
const object3 = new THREE.Mesh(
new THREE.SphereGeometry(0.5, 16, 16),
new THREE.MeshBasicMaterial({ color: '#ff0000' })
)
object3.position.x = 2
And a raycaster
const raycaster = new THREE.Raycaster();
const rayOrigin = new THREE.Vector3(-3, 0, 0);
const rayDirection = new THREE.Vector3(1, 0, 0);
raycaster.set(rayOrigin, rayDirection);
const intersects = raycaster.intersectObjects([object1, object2, object3])
console.log(intersects)
Logging the intersects array, we get this:
0: {distance: 2.5, point: Vector3, object: Mesh, uv: Vector2, face: {…}, …}
1: {distance: 2.5, point: Vector3, object: Mesh, uv: Vector2, face: {…}, …}
2: {distance: 2.5, point: Vector3, object: Mesh, uv: Vector2, face: {…}, …}
length: 3
Why is the distance the same for all spheres? Shouldn't the distances be 0.5, 2.5 and 4.5 respectively? What am I missing?

Threebox Tooltip in 3D models

I´ve been trying to enable tooltips on some imported 3D models, but it isnt working.
I already enabled tooltips in threbox, and I enabled tooltips in the options for the 3d element, as shown below.
tb = new Threebox(
map,
mbxContext,
{
realSunlight: true,
enableSelectingFeatures: true, //change this to false to disable fill-extrusion features selection
enableTooltips: true // change this to false to disable default tooltips on fill-extrusion and 3D models
}
);
var proptions = {
obj: './models/er.glb',
type: 'gltf',
scale: 10,
units: 'meters',
rotation: { x: 90, y: 0, z: 0 }, //default rotation
anchor: 'center',
adjustment: { x: 0, y: 0, z: 0.4 },
enableToltips: true
}
When i load the object i did the following:
tb.loadObj(proptions, function (model) {
model.setCoords(place);
model.addTooltip("A radar in the middle of nowhere", true);
model.setRotation({ x: 0, y: 0, z: Math.floor(Math.random() * 100) })
tb.add(model);
});
Although the object appears in the render, when I put the mouse above or i click it nothing shows the tooltip.
What am I missing ?
EDIT:
Following #jscastro response i changed the import in the top of my html page to <link href="./threebox-plugin/examples/css/threebox.css" rel="stylesheet" /> (the path is the correct to where the file is)
I also removed the enableTooltip: true in proptions.
Despite that it still does not work, Below i will leave the code as it is:
var origin = [-8.4, 41.20, 1];
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v11',
center: origin,
zoom: 11,
pitch: 30,
antialias: true
});
//Things related to dateTime ommited
window.tb = new Threebox(
map,
map.getCanvas().getContext('webgl'),
{
realSunlight: true,
enableSelectingFeatures: true, //change this to false to disable fill-extrusion features selection
enableTooltips: true // change this to false to disable default tooltips on fill-extrusion and 3D models
}
);
map.on('style.load', async function () {
await importarLinhas();
// stats
// stats = new Stats();
// map.getContainer().appendChild(stats.dom);
animate();
map.addLayer({
id: 'custom_layer',
type: 'custom',
renderingMode: '3d',
onAdd: function (map, mbxContext) {
var eroptions = {
obj: './models/stationBus.fbx',
type: 'fbx',
scale: 0.01,
units: 'meters',
rotation: { x: 90, y: 20, z: 0 }, //default rotation
anchor: 'center',
adjustment: { x: -0.1, y: -0.1, z: 0.4 }
}
var poptions = {
obj: './models/Busstop.fbx',
type: 'fbx',
scale: 0.03,
units: 'meters',
rotation: { x: 90, y: 20, z: 0 }, //default rotation
anchor: 'center',
adjustment: { x: -0.1, y: -0.1, z: 0.1 }
}
var proptions = {
obj: './models/er.glb',
type: 'gltf',
scale: 2.7,
units: 'meters',
rotation: { x: 90, y: 0, z: 0 }, //default rotation
anchor: 'center',
adjustment: { x: 0, y: 0, z: 0.4 }
}
allNos.forEach((element) => { //For each one of a list that i fill first
//center of where the objects are
var place = [element.lng, element.lat, 0];
//cylinder as "base" for each one of the 3d Models
**//in here i cant do the Tooltip for the object**
const geometry = new THREE.CylinderGeometry(0.6, 0.6, 0.15, 32);
const material = new THREE.MeshLambertMaterial({ color: 0x5B5B5B });
const cylinder = new THREE.Mesh(geometry, material);
var baseOptions = {
obj: cylinder,
anchor: 'center',
adjustment: { x: 0, y: 0, z: -0.4 }
}
let base = tb.Object3D(baseOptions);
base.setCoords(place);
base.setRotation({ x: 90, y: 0, z: 0 })
//The text is just for the test
base.addTooltip("A radar in the middle of nowhere", true);
// base.castShadow = true;
window.tb.add(base);
//next i check what type of element it is
//it can only be one at the same time, so i use different models for each type
if (element.tipo === "p") {
window.tb.loadObj(poptions, function (model) {
model.setCoords(place);
model.addTooltip("A radar in the middle of nowhere", true);
model.setRotation({ x: 0, y: 0, z: Math.floor(Math.random() * 100) })
// model.castShadow = true;
window.tb.add(model);
});
}
if (element.tipo === "er") {
window.tb.loadObj(eroptions, function (model) {
model.setCoords(place);
model.addTooltip("A radar in the middle of nowhere", true);
model.setRotation({ x: 0, y: 0, z: Math.floor(Math.random() * 100) })
// model.castShadow = true;
window.tb.add(model);
});
}
if (element.tipo === "pr") {
window.tb.loadObj(proptions, function (model) {
model.setCoords(place);
model.addTooltip("A radar in the middle of nowhere", true);
model.setRotation({ x: 0, y: 0, z: Math.floor(Math.random() * 100) })
// model.castShadow = true;
window.tb.add(model);
});
}
});
},
render: function (gl, matrix) {
window.tb.setSunlight(date, origin.center);
window.tb.update();
}
})
map.addLayer(createCompositeLayer());
map.on('SelectedFeatureChange', onSelectedFeatureChange);
});
EDIT
I downloaded the page you shared in the chat, and I found many different issues and mistakes in your code.
1. You're using the wrong property to enable the selection of 3D objects, you use enableSelectingFeatures: true, //change this to false to disable fill-extrusion features selection, that is for Mapbox fill-extrusions features as said in the comment, but not for 3D models and objects, you have to use enableSelectingObjects: true. Only adding this, your problem with the tooltips on mouse over will be solved.
tb = new Threebox(
map,
mbxContext,
{
realSunlight: true,
enableSelectingObjects: true, //enable 3D models over/selection
enableTooltips: true // enable default tooltips on fill-extrusion and 3D models
}
);
But I have found other issues...
2. Your models scale initialization is too small, so you are hiding them below the big shapes you have created. The scale of your bus stop is scale: 0.01 and you define a place which is on the ground var place = [element.lng, element.lat, 0];, so it's hidden inside this CylinderGeometry
If you use scale: 1 you will see how your bus stops raises from the cylinder.
3. Same with the bus, you initialize them with scale: 1, which make them be hidden below the tubes and cylinders you have created. If you initialize them with scale: 10, and you elevate them 5 meters from the floor let truck = model.setCoords([lngB, latB, 4]); then you will see them raising.
4. Your models have a wrong initialization params mixing anchor and adjustment. anchor: center will center the pivotal center of your object properly, but then you apply negative values to x and y (which means decenter the object), and a z value that elevates the pivotal center adjustment: { x: -0.1, y: -0.1, z: 0.4 }. If you want your model on altitude use the 3rd coord in setCoords.
5. Your Cylinders and Tubes for the bus stops and bus lines are huge, and also they have the wrong init params, as you set them below the ground level -0.4 units adjustment: { x: 0, y: 0, z: -0.4 } (something supported by Mapbox but very bad resolved and producing weird effects. My recommendation would be to make them almost flat and at the ground level with no adjustment param. const geometry = new THREE.CylinderGeometry(0.6, 0.6, 0.01, 32);.
Summarizing, check all of these changes and let me know if it works.

Autodesk Forge Element Rotation relative to World Coordination System

How do I get the rotation of an element relative to the world coordination system?
I'm getting the information of an element by the following:
this.viewerComponent.viewer.impl.hitTest(event.layerX, event.layerY, false);
The result of this function is the following
{distance: 186476.22640731235, point: X.Vector3, face: X.Face3, faceIndex: 0, fragId: 372, …}
distance: 186476.22640731235
point: X.Vector3 {x: 70297.79662079967, y: 8922.73091035225, z: 9109.446866256267}
face: X.Face3 {a: 0, b: 1, c: 2, normal: X.Vector3, vertexNormals: Array(0), …}
faceIndex: 0
fragId: 372
dbId: 1959
object: X.Mesh
eulerOrder: (...)
useQuaternion: (...)
uuid: "A3D04442-BB20-4E0C-B371-3A987D212255"
name: ""
type: "Mesh"
parent: undefined
children: []
up: X.Vector3 {x: 0, y: 1, z: 0}
position: X.Vector3 {x: 0, y: 0, z: 0}
rotation: X.Euler {_x: 0, _y: 0, _z: 0, _order: "XYZ", onChangeCallback: ƒ}
quaternion: X.Quaternion {_x: 0, _y: 0, _z: 0, _w: 1, onChangeCallback: ƒ}
scale: X.Vector3 {x: 1, y: 1, z: 1}
rotationAutoUpdate: true
matrix: X.Matrix4
elements: Float32Array(16) [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
__proto__: Object
matrixWorld: X.Matrix4
elements: Float32Array(16) [10, 0, 0, 0, 0, 10, 0, 0, 0, 0, 10, 0, 79719.9609375, -6109.12646484375,
1962.4998779296875, 1]
__proto__: Object
matrixAutoUpdate: true
matrixWorldNeedsUpdate: false
visible: true
castShadow: false
receiveShadow: false
frustumCulled: true
renderOrder: 0
userData: {}
geometry: h {id: 2265, attributes: {…}, __webglInit: undefined, byteSize: 28, vb: Float32Array(6),
…}
material: X.LineBasicMaterial {uuid: "E36F7B3D-C885-475C-9AA6-A3D1024F7687", name: "", type:
"LineBasicMaterial", side: 0, opacity: 1, …}
isTemp: true
dbId: 529
modelId: 1
fragId: 2264
hide: false
isLine: true
isWideLine: false
isPoint: false
themingColor: undefined
id: 1
__proto__: X.Object3D
As seen, we have the information matrix (local coordination system which is connected to the element coordination system) and matrixWorld which should be the transformation matrix for element -> global coordination system. How do I now get the angles out of the matrixWorld to know what is the rotation by the elmenent in relation to the world coordination system.
Hope it is clear what i want, thank you in advance.
If I understand you correctly you may try:
//Getting fragment info by fragId if necessary
//const matrixWorld = new THREE.Matrix4();
//const fragProxy = NOP_VIEWER.impl.getFragmentProxy(NOP_VIEWER.model, fragId)
//fragProxy.getWorldMatrix(matrixWorld);
const position = new THREE.Vector3();
const quaternion = new THREE.Quaternion();
const scale = new THREE.Vector3();
matrixWorld.decompose( position, quaternion, scale );
See more on extracting rotation here
Thank you. It's a similar approach I've taken. Your solution would probably work, too.
public onMouseMove(event) {
var snapper = new
Autodesk.Viewing.Extensions.Snapping.Snapper(this.viewerComponent.viewer, {});
const hitTestResult = this.viewerComponent.viewer.impl.snappingHitTest(event.layerX,
event.layerY);
snapper.snapping3D(hitTestResult);
// Arrow
const geometry = new THREE.CylinderGeometry(1, 800, 2000, 100);
const material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
const mesh = new THREE.Mesh(geometry, material);
mesh.rotateZ(this.arcSinFunction(normal.x, normal.y, normal.z, 0, 1, 0)[0]);
mesh.name = 'section-mesh';
mesh.position.set(snapper.getSnapResult().intersectPoint.x,
snapper.getSnapResult().intersectPoint.y, snapper.getSnapResult().intersectPoint.z);
if (!this.viewerComponent.viewer.overlays.hasScene('section-scene')) {
this.viewerComponent.viewer.overlays.addScene('section-scene');
}
this.viewerComponent.viewer.overlays.addMesh([mesh, mesh_test], 'section-scene');
}
public arcSinFunction(n1: number, n2: number, n3: number, u1: number, u2: number,
u3:
number): Array<number> {
var zähler: number = Math.abs(n1 * u1 + n2 * u2 + n3 * u3);
// console.log(zähler);
var nenner: number = (Math.sqrt(n1 * n1 + n2 * n2 + n3 * n3)) * (Math.sqrt(u1 * u1 +
u2 * u2 + u3 * u3));
// console.log(nenner);
var resultRadian: number = Math.asin(zähler / nenner);
// console.log(resultRadian);
var pi = Math.PI;
var resultDegree = resultRadian * (180 / pi);
// console.log(resultDegree);
var res: Array<number> = [resultRadian, resultDegree];
// console.log(res);
return res;
}
Best regards

Model not rendering on three.js

I am new to Three.js. I was trying to load a STL model using the STLLoader from the examples. The model I am trying to load is the Eiffel Tower model. I downloaded the STL file which is in ASCII format and almost 33 MB in size. I have the following setup to display the model:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>My first three.js app</title>
<style>
body { margin: 5% auto; }
canvas { width: 80%; height: 80% }
#progress {
margin-bottom: 2%;
min-width: 50%;
}
</style>
<script src="js/three.js"></script>
<script src="js/STLLoader.js"></script>
</head>
<body>
<div id="progress"></div>
<script>
// window properties
const windowWidth = window.innerWidth;
const windowHeight = window.innerHeight;
// camera properties
const FOV = 35;
const ASPECT_RATIO = windowWidth / windowHeight;
const NEAR = 0.1;
const FAR = 1000;
// scene settings
const SCENE_BKG = new THREE.Color("rgb(220,220,220)");
const scene = new THREE.Scene();
scene.background = SCENE_BKG;
const camera = new THREE.PerspectiveCamera( FOV, ASPECT_RATIO, NEAR, FAR );
const STLLoader = new THREE.STLLoader();
STLLoader.load('./sample_stl/Eiffel_tower_sample.STL', function(geometry) {
console.dir(geometry);
const materials = [];
const nGeometryGroups = geometry.groups.length;
let colorMap = []; // Some logic to index colors.
let material;
// create a random colorMap
let startColor = 0x010101;
let clr = startColor;
let count = 0;
while (count++ < nGeometryGroups) {
colorMap.push(clr);
clr = ( parseInt(clr, 16) + startColor ).toString();
}
console.log(colorMap);
for (let i = 0; i < nGeometryGroups; i++) {
material = new THREE.MeshPhongMaterial({
color: colorMap[i],
wireframe: false
});
}
materials.push(material);
const mesh = new THREE.Mesh(geometry, materials);
console.dir(mesh);
scene.add(mesh);
// should i call animate here?
}, function (xhr) {
// show progress here
progressBar.innerHTML = `<span style="color: green;">${(xhr.loaded/xhr.total) * 100}%</span> have been loaded`;
}, function(err) {
console.error('[!] Fatal Error: Could not load model');
console.error(err);
});
const renderer = new THREE.WebGLRenderer();
renderer.setSize( windowWidth, windowHeight );
const progressBar = document.querySelector('#progress');
document.body.appendChild( renderer.domElement );
const animate = () => {
requestAnimationFrame(animate);
renderer.render(scene, camera);
};
camera.position.set(0, 0, 10);
animate();
</script>
</body>
</html>
There are two things I am not sure about. First, what is the colorMap array? I looked at the MeshPhongMaterial class documentation and figured out it was a hex color value. I copied this code directly from the STLLoader example folder here. I found a quick hack to generate some hex colors and populate the colorMap array (an empty array was throwing errors). Secondly, where should I call the animate() function? I tried calling it inside the modelLoaded handler and also outside it with the only difference being that inside the handler, it throws Violation: handler took 500ms. I checked the networks tab on both Firefox and Chromium to see that the STL file was loaded properly. I also printed the Mesh object in the console which is as follows:
Mesh
castShadow: false
children: []
drawMode: 0
frustumCulled: true
geometry: BufferGeometry
attributes: {position: Float32BufferAttribute, normal: Float32BufferAttribute}
boundingBox: null
boundingSphere: Sphere {center: Vector3, radius: 71.76963889659893}
drawRange: {start: 0, count: Infinity}
groups: [{…}]
index: null
morphAttributes: {}
morphTargetsRelative: false
name: ""
type: "BufferGeometry"
userData: {}
uuid: "28A4B269-2828-477D-9C6D-5C9A30E95A7F"
_listeners: {dispose: Array(1)}
drawcalls: (...)
id: 7
offsets: (...)
__proto__: EventDispatcher
layers: Layers
mask: 1
__proto__: Object
material: Array(1)
0: MeshPhongMaterial {uuid: "1E33986A-A979-49C0-ADF5-823CACC6F3AA", name: "", type: "MeshPhongMaterial", fog: true, blending: 1, …}
length: 1
__proto__: Array(0)
matrix: Matrix4
elements: Array(16)
0: 1
1: 0
2: 0
3: 0
4: 0
5: 1
6: 0
7: 0
8: 0
9: 0
10: 1
11: 0
12: 0
13: 0
14: 0
15: 1
length: 16
__proto__: Array(0)
__proto__: Object
matrixAutoUpdate: true
matrixWorld: Matrix4
elements: Array(16)
0: 1
1: 0
2: 0
3: 0
4: 0
5: 1
6: 0
7: 0
8: 0
9: 0
10: 1
11: 0
12: 0
13: 0
14: 0
15: 1
length: 16
__proto__: Array(0)
__proto__: Object
matrixWorldNeedsUpdate: false
name: ""
parent: Scene
autoUpdate: true
background: Color {r: 0.8627450980392157, g: 0.8627450980392157, b: 0.8627450980392157}
castShadow: false
children: [Mesh]
fog: null
frustumCulled: true
layers: Layers {mask: 1}
matrix: Matrix4 {elements: Array(16)}
matrixAutoUpdate: true
matrixWorld: Matrix4 {elements: Array(16)}
matrixWorldNeedsUpdate: false
name: ""
overrideMaterial: null
parent: null
position: Vector3 {x: 0, y: 0, z: 0}
quaternion: Quaternion {_x: 0, _y: 0, _z: 0, _w: 1, _onChangeCallback: ƒ}
receiveShadow: false
renderOrder: 0
rotation: Euler {_x: 0, _y: 0, _z: 0, _order: "XYZ", _onChangeCallback: ƒ}
scale: Vector3 {x: 1, y: 1, z: 1}
type: "Scene"
up: Vector3 {x: 0, y: 1, z: 0}
userData: {}
uuid: "3F9C4993-4CB4-4541-9C64-34FCBB12B1E3"
visible: true
_listeners: {dispose: Array(2)}
eulerOrder: (...)
id: 4
modelViewMatrix: Matrix4 {elements: Array(16)}
normalMatrix: Matrix3 {elements: Array(9)}
useQuaternion: (...)
__proto__: Object3D
position: Vector3 {x: 0, y: 0, z: 0}
quaternion: Quaternion {_x: 0, _y: 0, _z: 0, _w: 1, _onChangeCallback: ƒ}
receiveShadow: false
renderOrder: 0
rotation: Euler {_x: 0, _y: 0, _z: 0, _order: "XYZ", _onChangeCallback: ƒ}
scale: Vector3 {x: 1, y: 1, z: 1}
type: "Mesh"
up: Vector3 {x: 0, y: 1, z: 0}
userData: {}
uuid: "72BA29AF-F939-45F8-869A-D074E6696D7F"
visible: true
eulerOrder: (...)
id: 10
modelViewMatrix: Matrix4 {elements: Array(16)}
normalMatrix: Matrix3 {elements: Array(9)}
useQuaternion: (...)
__proto__: Object3D
This is the printed Mesh object. I am not sure what's wrong and would be glad if someone can explain me how to use the colorMap property and also give me a definitive answer on the animate function calling scope.
EDIT
Added a fiddle here.
First, what is the colorMap array?
The code from your example assumes that the model's geometry has multiple groups. If this is true, it's possible to assign multiple materials to a single 3D object. However, it's not mandatory to do so. If you want just a single material color, do this:
const material = new THREE.MeshPhongMaterial( { color: 0x0000ff } );
const mesh = new THREE.Mesh( geometry, material );
Secondly, where should I call the animate() function?
three.js examples normally have an init() and an animate() function. Meaning you start animating right after initializing the scene (creating camera, renderer, lights etc.). You can do this also in your application, however the STL file will pop in as soon as its loading and parsing progress is finished. As an alternative, you can also start animating in the onLoad() callback. It really depends on your use case (so there is no right or wrong).
three.js R111

custom phong shader envMap flipped

I use a ShaderMaterial that is a complete copy of the default Phong shader (I use shaderChunks).
My problem is that the envMap is flipped over X...
Here is what I get:
And what I want:
I tried to access cubeCamera.renderTarget.texture to use repeat.x = -1 and wrapS = THREERepeatWrapping.RepeatWrapping but it does absolutely nothing...
var cubeCamera = new THREE.CubeCamera(0.01, 500, 256);
scene.add(cubeCamera);
var sphereMaterial = new THREE.ShaderMaterial({
uniforms: THREE.UniformsUtils.merge([
THREE.UniformsLib.common,
THREE.UniformsLib.aomap,
THREE.UniformsLib.lightmap,
THREE.UniformsLib.emissivemap,
THREE.UniformsLib.bumpmap,
THREE.UniformsLib.normalmap,
THREE.UniformsLib.displacementmap,
THREE.UniformsLib.fog,
THREE.UniformsLib.lights,
THREE.UniformsLib.shadowmap,
{
emissive: {
type: "c",
value: new THREE.Color(0x000000)
},
specular: {
type: "c",
value: new THREE.Color(0x111111)
},
shininess: {
type: "f",
value: 30
},
envMap: {
type: "t",
value: cubeCamera.renderTarget
}
}
]),
vertexShader: require("../../shaders/phong.vert.glsl"),
fragmentShader: require("../../shaders/phong.frag.glsl"),
blending: THREE.AdditiveBlending,
depthWrite: false,
transparent: true,
opacity: 1,
lights: true
});
sphereMaterial.envMap = true;
EDIT:
JSFIDDLE example
To get the reflection you are after, set
sphereShaderMaterial.uniforms.flipEnvMap.value = 1;
I'm not sure when this actually gets set on the MeshPhongMaterial, I suspect somewhere in the WebGLRenderer it does some checks and sets this. The WebGLRenderer does many things to the different types of materials which makes them a little hard to just extend easily.

Resources