GL_INVALID_OPERATION during three js switching material - three.js

I am learning three js and I encounter some issue which is not clear to me. I have one mesh object and and 3 materials (MeshBasicMaterial,MeshNormalMaterial,MeshLambertMaterial). In my example, I swith one material to another.
There is something I don't understand.If i initialize my mesh object with one material other than the MeshBasicMaterial, I can switch perfectly.
But if I initialize my mesh object with the MeshBasicMaterial, I can't switch to another material. Within the webbroswer console, I got an error such as GL_INVALID_OPERATION attemp to acces out of range vertices attribute 1.
What is the explanation of that?

Related

I can't get the aoMap showing in three.js using a glb/gltf asset

I’m having a hard time getting an aoMap working in three.js…
I have a glb asset with an aoMap on the red channel or something. When I bring it into to the babylon viewer, I can see the ao just fine, but it wont show up in the three.js viewer or my project. I think this has something to do with a second set of uvs, but I can't find a resource that involves doing that on top of using the gltf loader… I really don't know what to do here. Any response would be greatly appreciated!
Here is my code (I’m using a html-canvas as the texture)
And I get the model’s geometry and diffuse texture (all white) as desired, but the aomap isnt showing…
code
babylon viewer
three.js viewer
working application with shadows included in diffuse
not working, diffuse is just white, and aoMap is not showing
You're right about needing a second set of UVs. The reason behind this is that diffuse textures often repeat (think of a brick wall, or checkered t-shirt). AO shading, however, is more likely to be unique on each part of the geometry, so it's almost never repetitive. Since this often would need an alternative UV mapping method, the default is to use a second set of UVs.
You could do 2 things:
Re-export your GLTF asset with a duplicate set of UVs.
Duplicate existing UVs in Three.js by creating a new BufferAttribute in your geometry:
// Get existing `uv` data array
const uv1Array = mesh.geometry.getAttribute("uv").array;
// Use this array to create new attribute named `uv2`
mesh.geometry.setAttribute( 'uv2', new THREE.BufferAttribute( uv1Array, 2 ) );
.getAttribute and .setAttribute are methods of BufferGeometry, if you want to read more about them.

Render scene onto custom mesh with three.js

After messing around with this demo of Three.js rendering a scene to a texture, I successfully replicated the essence of it in my project: amidst my main scene, there's a now sphere and a secondary scene is drawn on it via a THREE.WebGLRenderTarget buffer.
I don't really need a sphere, though, and that's where I've hit a huge brick wall. When trying to map the buffer onto my simple custom mesh, I get an infinite stream of the following errors:
three.js:23444 WebGL: INVALID_VALUE: pixelStorei: invalid parameter for alignment
three.js:23557 Uncaught TypeError: Cannot read property 'width' of undefined
My geometry, approximating an annular shape, is created using this code. I've successfully UV-mapped a canvas onto it by passing {map: new THREE.Texture(canvas)} into the material options, but if I use {map: myWebGLRenderTarget} I get the errors above.
A cursory look through the call stack makes it look like three.js is assuming the presence of the texture.image attribute on myWebGLRenderTarget and attempting to call clampToMaxSize on it.
Is this a bug in three.js or am I simply doing something wrong? Since I only need flat rendering (with MeshBasicMaterial), one of the first thing I did when adapting the render-to-texture demo above was remove all trace of the shaders, and it worked great with just the sphere. Do I need those shaders back in order to use UV mapping and a custom mesh?
For what its worth, I was needlessly setting needsUpdate = true on my texture. (The handling of needsUpdate apparently assumes the presence of a <canvas> that the texture is based on.)

Why do I need to update uvs?

I'm working with the three.js editor where I parse an object from JSON format. As usual it first parses the materials and geometries, then I create meshes from it. While parsing materials I also load textures. The issue now is that I have to call...
object.geometry.uvsNeedUpdate = true;
object.geometry.buffersNeedUpdate = true;
... after the image for the texture completely loaded - but why?! The geometry never changed before, neither did its uvs or anything like it. It's still the plain old geometry, yet I always get a GL ERROR :GL_INVALID_OPERATION : glDrawElements: attempt to access out of range vertices in attribute 2 when trying to render. It only works with this "hack" although the geometry is always the same.
In my opinion it should also work perfectly when I update the uvs after object creation (or not at all). I didn't find anything in the three.js editor code that would update the geometry or its faceVertexUvs.
I know it's a bit of an abstract problem, I'm mainly looking for some hints or insights why this hack might be necessary.
Thanks!
Three.js "guesses" whether uvs are needed according to your used textures in bufferGuessUVType. If you want to preallocate uv buffers you can either init a map attribute with an empty THREE.Texture, update the geometry after the map was assigned, etc.

lightMap / specularMap / shading with meshBasicMaterial

I'm currently working on something along the lines of a plugin for another program to add 3D capability to it, so I'm trying to put all the functionality i can from three.js into it, with the added goal of this being a good way to learn all the functionality of three.js firsthand.
I'm running into an issue now as i implement textures and materials that with mesh basic material, setting some things which the documentation on the main threejs.org site shows are features, doesn't actually do anything.
when i set a texture for either specularmap or lightmap nothing is actually showing up. Im pretty sure its not a mistake im making because setting the texture of the map works, but trying to set this same texture for the specularMap or lightMap is doing nothing. Does a regular texture work for these, or do i have to do something different?
I'd also like to know what the shading property does for mesh basic, because as far as i can see setting it to smoothshading/flatshading/noshading is doing nothing aswell.
MeshBasicMaterial does not respond to lights. Change your material to MeshLamberMaterial or MeshPhongMaterial, for example.
For MeshBasicMaterial and MeshLambertMaterial, the specularMap is used only to modulate the reflection when an environment map is used.
For any material, lightmaps require a second set of UVs. geometry.faceVertexUvs[ 0 ] contains the usual set of UVs; for a lightmap, you need to add geometry.faceVertexUvs[ 1 ], a second set of UVs.
For MeshBasicMaterial, the shading property only applies when an environment map is used. SmoothShading will yield smooth reflections; FlatShading will yield faceted reflections.
three.js r.66

texture mapping different objects in three.js

We are studying on product designer project. Designer is ready.
I want to do 3d preview result with three.js.
How can we texture one side of phone case? or can we border texture mapping?
OBJLoader version:
http://www.shopilife.com/baskiburada/viewer/viewer_4.html
And some obj files cannot be textured. Error is "GL_INVALID_OPERATION : glDrawElements: attempt to access out of range vertices in attribute 2"
http://www.shopilife.com/baskiburada/viewer/viewer2.html
First, regarding re-texturing the back vs. front of the phone case. The approach here is to seperate the UV coordinates on the model itself. This way you have two sets of materials/textures/UVs. Then during runtime you load them both using a MeshFaceMaterial to load the two materials in an array like so:
materialArray.push(THREE.BasicMeshMaterial({color: 0xff0000})); //use whatever Material type you'd like of course
materialArray.push(THREE.BasicMeshMaterial({color: 0x0000ff}));
var multipleMaterial = new THREE.MeshFaceMaterial(materialArray);
phoneCaseMesh= new THREE.Mesh( geometry, multipleMaterial );
Then when you want to switch one out you would grab the mesh and change the mapping to the desired side something like:
phoneCaseMesh.material.materials[1].map = THREE.ImageUtils.loadTexture( 'newtexture.jpg' );
Second, regarding the Error on you second sample, WestLangley is correct the OBJ file has no UV coordinates to map to, so the index is out of bounds when you apply a texture. If you look at both OBJ files your iphone4.obj has vt entities while the untitled.obj is just v and f. Hope that helps

Resources