14
$\begingroup$

I'm trying to reproduce a textured head in Mathematica, and I'm using a kind of 'net' of a head which contains all the features on the face. The texture looks like this: enter image description here

which is supposed to look something like this:enter image description here

Here's the code I'm using.

ListSurfacePlot3D[Import["inputImage.obj", "VertexData"], 
PlotStyle -> Texture[texture], Mesh -> None, MaxPlotPoints -> 80, 
TextureCoordinateFunction -> ({#1, -#2, #3} &)]

which gives meenter image description here

Another problem is that the texture is reflected about the origin (ie the face is plastered on the back of the head as well). It should instead be black on the back of the head mesh. I suppose this is suppose to do with the head being centered at the origin. I also need to have the texture to 'follow' the head when I change the coordinates of the mesh later on.

I have attempted using

Graphics3D[
 {EdgeForm[],
  Texture[texture],
  GraphicsComplex[mesh,
   Polygon[polygon, VertexTextureCoordinates -> mesh]]}]

but it gives me this instead

enter image description here

I need to be able to reproduce this in Mathematica as I have some coordinate transformations which I need to apply, and thereafter, 'wrap' the mesh with the texture. Are these possible?

EDIT: The link to the model is located https://git.io/viJXD

EDIT 2: I've tried converting the OBJ to PLY and I did this

Import["inputImage.ply", "UserExtensions"][[2]]
Import["inputImage.ply", "UserExtensions"][[3]]

which gave an output of

"texture_u" -> {..}
"texture_v" -> {..}

where .. was a bunch of numbers which had a Length of 3066 for both. My guess was that these are texture coordinates (where u is horizontal and v is vertical) as per the links provided by Rahul Narain.

I attempted to create a list of coordinates from these two list in the following manner

texturecoord = {Import["inputImage.ply", "UserExtensions"][[2]][[2]], 
   Import["inputImage.ply", "UserExtensions"][[3]][[2]]} // Transpose

Then, I tried doing

Graphics3D[
 {EdgeForm[],
  Texture[texture],
  GraphicsComplex[mesh,
   Polygon[polygon, VertexTextureCoordinates -> mesh]]}]

But that gives me this

enter image description here

$\endgroup$
6
  • 1
    $\begingroup$ Could you link to the texture and the face model as well? $\endgroup$
    – rm -rf
    Oct 16, 2013 at 18:14
  • 4
    $\begingroup$ ListSurfacePlot3D is quite appropriate for Halloween. That face is.... scary. $\endgroup$ Oct 16, 2013 at 22:09
  • $\begingroup$ I've added a link at the bottom. $\endgroup$
    – user10035
    Oct 17, 2013 at 1:52
  • 1
    $\begingroup$ The problem is that the mesh in the OBJ file comes equipped with texture coordinates, but Mathematica throws them away when importing it. Thus it is not possible to correctly map the texture on the imported mesh, unless you write your own OBJ parser that retains the texture coordinates. Fortunately the OBJ file format is quite easy to parse, but someone with more free time than me should do it. $\endgroup$
    – user484
    Oct 17, 2013 at 23:55
  • 2
    $\begingroup$ @RahulNarain Have you seen this? You suggestion has been implemented. $\endgroup$
    – Szabolcs
    Jun 26, 2014 at 0:09

2 Answers 2

2
$\begingroup$

Not sure if this helps, but if you play with the texture function coordinates and change the lighting you can get something that looks reasonable:

ListSurfacePlot3D[
 Import["inputImage.obj", "VertexData"], 
 PlotStyle -> Texture[texture], Mesh -> None, MaxPlotPoints -> 80, 
 TextureCoordinateFunction -> (If[#3 > 0.3, {0.7 #1 + 0.15, -#2 - 0.06}, {0.5, 0.9}] &), 
 Lighting -> "Neutral"]

Change the 0.3 if you need more or less of the back colored black.

Mathematica graphics

Mathematica graphics

enter image description here

$\endgroup$
5
  • $\begingroup$ I have decided to make a switch to using Graphics3D, because it is computationally more efficient and I do not have to worry about rough edges. VertexTextureCoordinate is to GraphicsComplex as what TextureCoordinateFunction is to ListSurfacePlot3D. The main difference is that VertexTextureCoordinate uses a series of vertices as I understand it, to match the texture coordinate to the surface. Do you have any suggestions as to how I could tweak this code? `Graphics3D[ {EdgeForm[], Texture[texture], GraphicsComplex[mesh, Polygon[polygon, VertexTextureCoordinates -> mesh]]}] $\endgroup$
    – user10035
    Oct 18, 2013 at 8:24
  • $\begingroup$ I require an exact mapping. Would that be possible? $\endgroup$
    – user10035
    Oct 21, 2013 at 10:04
  • $\begingroup$ @user10035 See the comment of Rahul above. $\endgroup$ Oct 21, 2013 at 10:31
  • $\begingroup$ I've converted the format to .PLY and managed to extract the texture coordinates and replotted the mesh as seen in the second edit in my original post. However, it still doesn't seem to work. Any insights on this? $\endgroup$
    – user10035
    Oct 22, 2013 at 10:53
  • $\begingroup$ @user10035 I would love to dive into this, but unfortunately don't have time to do that at this moment. $\endgroup$ Oct 22, 2013 at 11:18
2
$\begingroup$

This problem came up here recently where someone wanted to do the same thing, but with a .obj file containing 264k polygons. I wrote a code for it, but my machine just wouldn't give an answer. So I found this question where the .obj file has only 6k polygons.

importOBJ[objfile_String, texturefile_String, 
   opts : OptionsPattern[]] := 
  Module[{image, raw, verts, tverts, pgons, vertcoords},
   image = Import[texturefile];
   raw = Import[objfile, "Table"];
   If[
    Head /@ {image, raw} =!= {Image, List},
    Missing["NotAvailable"],
    verts = Rest /@ Cases[raw, {"v", __}];
    tverts = Rest /@ Cases[raw, {"vt", __}];
    {pgons, vertcoords} = 
     Cases[raw, {"f", 
         b__} :> (ToExpression@StringSplit[#, "/"] & /@ {b})] // 
      Transpose[#, {2, 3, 1}] &;
    Graphics3D[
     GraphicsComplex[verts,
      {EdgeForm[], Texture[image],
       Polygon[#1,
          VertexTextureCoordinates -> tverts[[#2]]] & @@@ 
        Thread[{pgons, vertcoords}]}],
     opts]
    ]
   ];

Here are paths to the 3D and texture files,

objfile="https://git.io/viJXD";
texturefile="https://i.stack.imgur.com/LmTQl.jpg";

And here is the disembodied head:

importOBJ[objfile, texturefile, Boxed -> False, Lighting -> "Neutral"]

enter image description here

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.