Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

texture() ignoring uvs for .obj file #4866

Closed
1 of 13 tasks
kieranbrowne opened this issue Oct 21, 2020 · 8 comments
Closed
1 of 13 tasks

texture() ignoring uvs for .obj file #4866

kieranbrowne opened this issue Oct 21, 2020 · 8 comments

Comments

@kieranbrowne
Copy link

kieranbrowne commented Oct 21, 2020

Hi there,

I'm trying to import a basic 3d .obj file and texture into p5js, but the texture appears to be ignoring the uv information in the obj file and misplacing the texture. I've written the equivalent program in processing 3 and it display correctly, so I can be pretty sure it's not an issue with the obj and texture files.

Am I doing something silly, or is this a genuine bug?

Most appropriate sub-area of p5.js?

  • Accessibility (Web Accessibility)
  • Color
  • Core/Environment/Rendering
  • Data
  • Dom
  • Events
  • Image
  • IO
  • Math
  • Typography
  • Utilities
  • WebGL
  • Other (specify if possible)

Details about the bug:

  • p5.js version: 1.1.9
  • Web browser and version: Chrome: 86.0.4240.80 and Firefox: 81.0.2
  • Operating System: MacOSX 10.15.6
  • Steps to reproduce this: Load an obj file and texture into p5 with loadModel and loadImage.
    The p5 code with all the necessary assets can be found here: https://editor.p5js.org/kbrowne/sketches/o_PYbAgLl

And here is the equivalent processing 3 code which textures correctly:

PShape mod;
PImage tex;

void setup() {
  size(400, 400, P3D);

  mod = loadShape("TreeFinger_L_03.obj");
  tex = loadImage("dif_arm.png");
  mod.setTexture(tex);
  noStroke();
}

void draw() {
  background(220);
  translate(width/2, height/2);
  scale(4);
  rotateX(frameCount * 0.01);
  rotateY(frameCount * 0.01);

  shape(mod, 0, 0);
}
@welcome
Copy link

welcome bot commented Oct 21, 2020

Welcome! 👋 Thanks for opening your first issue here! And to ensure the community is able to respond to your issue, be sure to follow the issue template if you haven't already.

@stalgiag
Copy link
Contributor

stalgiag commented Oct 21, 2020

Hi! I know that the UVs are parsing correctly with some files but maybe there is a need to compare the UV parsing here to what is done in Processing to provide greater support.

Anyone is welcome to take a look.

@kieranbrowne
Copy link
Author

So I figured out that the y values for the uvs are inverted.

It's possible to reverse them like so:

  for(let i=0; i< mod.uvs.length; i++) {
    mod.uvs[i][1] = 1.-mod.uvs[i][1];
  }

And this fixes the problem. See updated sketch: https://editor.p5js.org/kbrowne/sketches/o_PYbAgLl

This leaves open the question of why uvs appear to be parsed correctly for the file @stalgiag mentioned.
I rendered the capsule object and texture into processing and it displayed like so:

processing

But the equivalent code in p5 looks like this:

p5

So it seems like p5 and processing are using the uv y values inversely.

@stalgiag
Copy link
Contributor

Thank you @kieranbrowne! I think we should follow Processing on this. It appears that the lower-left pixel is 0,0 in most model format conventions and WebGL is the only one that needs to flip. This was likely not known when first implementing the loader.

@myselfhimself
Copy link
Contributor

myselfhimself commented Jan 28, 2021

Hello,
just dug in the code.
IHMO since OBJ is only concerned with bad UV flipping, the OBJ geometry importer only should be patched, not the GL renderer for any geometries. I got into thinking this by reading this WebGL doc for p5, especially the Geometry section.
The OBJ format requires vt U, V, W lines to describe the texture coordinates of vertices, per this stack overflow post especially, where the same flipped Y (ie. V) coordinate issue is raised. One that very post's comments states that the W coordinate (eg. the 3rd parameter if ever, found after the 'vt' keyword) is never used.
Looking at the p5js loadModel OBJ parseObj(...) sub-function, it seems that the UV texture coordinates parsing does happen with no V coordinate flipping:

const texVertex = [parseFloat(tokens[1]), parseFloat(tokens[2])];


      } else if (tokens[0] === 'vt') {
        // Check if this line describes a texture coordinate.
        // It will have two numeric parameters.
        const texVertex = [parseFloat(tokens[1]), parseFloat(tokens[2])];
        loadedVerts[tokens[0]].push(texVertex);

where the texVertex should theoretically be the same with 1 - V inversion for the second coordinate:
const texVertex = [parseFloat(tokens[1]), 1- parseFloat(tokens[2])];

Who is willing to patch and test this? I have never built p5js's main .js file yet

myselfhimself added a commit to myselfhimself/p5.js that referenced this issue Jan 28, 2021
Testing this as WebGL requires a flipped/inverted V texture coordinate
@myselfhimself
Copy link
Contributor

The added PR is ready for testing

@myselfhimself
Copy link
Contributor

Here is a duplicated arm scene with a patched p5.js (uncompressed so 3.7MB)
https://editor.p5js.org/myselfhimself/sketches/yr8IQoK5I
This is indeed fixes the non-inverted V texture coordinate problem, and does not require you to for-loop and fix that in sketch.js

However, the capsule example with that patched p5.js file leads to a vertically flipped UV mapping visually:
https://editor.p5js.org/myselfhimself/sketches/V9ic4WvPg

Maybe we should all take care of how we export our .OBJ files... Blender3d's OBJ exporter for example allows to flip the forward and upward axes:
image
... and these settings do not work well for me.. my textures are always flipped in some way...

Hi! I know that the UVs are parsing correctly with some files but maybe there is a need to compare the UV parsing here to what is done in Processing to provide greater support.

Anyone is welcome to take a look.

Here is the related source in Processing (java), which states even in its preceding code commenting that the V values are inverted:
https://github.com/processing/processing/blob/94144be998354ecf7a06d5301b7b4fab72df724c/core/src/processing/core/PShapeOBJ.java#L215


          } else if (parts[0].equals("vt")) {
            // uv, inverting v to take into account Processing's inverted Y axis
            // with respect to OpenGL.
            PVector tempv = new PVector(Float.valueOf(parts[1]).floatValue(),
                                        1 - Float.valueOf(parts[2]).
                                        floatValue());
            texcoords.add(tempv);
            readvt = true;

So unless OpenGL and WebGL differ in behaviour and V x Y axes directions, I think that p5.js should follow Processing's behaviour and invert the V values...

stalgiag added a commit that referenced this issue Jan 29, 2021
#4866 V texture coordinate inversion on OBJ loadModel
@stalgiag
Copy link
Contributor

closed with #5017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants