Unveiling the Code: Insights, Inspiration, and Innovation

Mapping Textures to Geometry

Yesterday I had the goal of loading an image of a sculpted prim from Second Life within a web browser and display a 3D model of it using the Three.js library. I ran into a few issues and here are some fun excuses.

  • I haven’t used Second Life much since 2012
  • I’m new to scripting in 3D environments
  • I’m unfamiliar with NURBS modeling
  • I’ve not used 3D modeling software in a professional manner since 1995 to create a logo

However, the excuses are not enough. There are plenty of reasons to get past this problem.

  • I’ve been programming a variety of languages since the early 80’s
  • I’ve used various forms of 3D modeling software over the years
  • I know how to find information through search engines
  • Large language models such as OpenAI ChatGPT, Google Bard Gemini and GitHub Copilot are able to hold conversations and give some pretty good information on just about anything.

With that said, lets set some goals for today.

  • Display textures on the models to ensure the UV mapping is configured correctly
  • Figure out why models are a mess with some faces appearing where they shouldn’t
  • Identify if I’m using the correct pixels from the sculpted prim image
  • Address the clipping effect of some of the faces. It may be related to having two faces in the same location.
  • Display model according to different settings for Length of Distance (LOD) rendering
  • Export the object as a “normal” file format
  • Export as a Sculpted prim image and see if it appears correctly in Second Life
  • NURBS – Will I ever get to it?

Technically, I’m working with 1 degree NURBS at the moment, but that’s not utilizing the power of NURBS at all. By default, NURBS models usually start out with 3 degrees. Before I get to NURBS, I need to get the mesh figured out with complete accuracy.

Texture Maps

I retrieved a bunch of sculpted prim images yesterday. Now its time to grab their skins and see how they are applied. The first thing that happened is that I was prompted to download the latest viewer. Once I got in, I started to edit my comment box and got a message supporting GLTF Physically Based Rendering materials with a link to Physically Based Rendering (PBR). Hmm… I didn’t realize that they used GLTF. Since Three.js uses it as default, it seems that this is an industry wide format now.

GLTF BPR Materials Support

Going through my inventory hunting for textures, I found 56 additional sculpted prim images that I had worked on. I found a few textures and added them. Most of my models that I created didn’t need textures, or could use some of the standard ones like a wood texture, or I just needed to change its color. However, I found enough texture maps to have a small sample.

There were so many textures that rather then add them all by hand to the dropdown list, I created a node script to read the directory of all of the images and create a JSON file that the web page would fetch. Once that was done, I added a drop-down list to load the textures. I started learning about how to load, update, and dispose textures properly.

Unfortunately I ran into a bit of a problem. Most textures made the models appear dark. Applying different textures started to change the color of the mesh, but didn’t appear to apply the full image – or any of it for that matter.

Applying a blue fish texture map

I suspect this has to do with “normals”. I had to call computeVertexNormals in order to get the mesh to receive light. The documentation states that the UV mapping of textures maps to the normals of the sculpted prim image. Perhaps my vertices were not read in the correct order. Maybe the fact that I needed to compute the vertex normals should have been a flag that something wasn’t done properly. I’m reminded of Gaias transcript of working with the bottom row first, where I’m reading top to bottom. Due to the nature of sculpted prims, that really shouldn’t matter as flipping the image vertically would result in the same model being displayed. Or would it?

I started looking and found that I could update the UV mapping manually, and code samples started off with computing a bounding sphere with geometry. I created a function called updateUvMapping passing the geometry, horizontal and vertical segments. Github Copilot suggested to create some code that created an array of UVs based on looping through the segments and applying it to the uv attribute. I noticed immediate results as various models were now showing the textures. Still, something was off with the “quads” as the texture on the UFO seemed to spiral. At least I had a visual representation of what was going on with the faces now.

Spiraling texture on UFO

With that said, it was time to get more control over the camera. I added some sliders to allow control over the models rotation, and added checkboxes next to each one to flag if the axis should be rotated or not. I then moved onto the camera itself. I created a few buttons for top, bottom, left, right, front, back, isometric, and perspective views. It took a bit of work, but I was able to get the camera into position so that the model took up as much of the view as possible. I ran into a bit of a problem with the top and bottom views where the model wasn’t fully vertical. The fix seemed to be setting the camera’s up axis to 0, 0, -1 instead of the default 0, 1, 0. I’m a bit confused as to why that would result in a slight angle.

Angled model on bottom view

Well, I’ve got other stuff to do tonight. Signing off…

… and I’m back. Lots of events tonight.

I’m not sure if I should attack the quad faces, spiral texturing, horizontal stitching, or the odd angles for top & bottom camera angles. Lets go for the quads since I can visually see progress now.

The first thing I tried was to change the order that I added each triangle in a quad. Nothing happened. Next I decided to change one of them to be added clockwise. Sure enough, this flipped the normal mapping and half of each quad was now invisible because the face was facing away from the camera, inside the center of the model.

Half of the quad faces facing the wrong direction.

This confirms that the order of vertices are correct. I get the feeling that the 33rd column is an issue here. It sort of explains why everything seems to be off by one quad making a checkerboard pattern.

Checkerboard pattern

When reading the control vertices from the sculpted prim, I was skipping odd pixels. I decided to use the last pixel in each column. I immediately saw some strait lines in the texture.

Strait lines from a texture

I’m getting somewhere. Looking at other models, I noticed that “spiderwebs” and random faces were no longer an issue.

Floating stairs with random faces
Floating stairs look normal
Rails with spider webs
Rails without spider webs

The texture seems off. Not only is it rotated, but the edges aren’t mapping properly. I needed to find a segmenting grid pattern to help me distinguish what cell I was looking at, and if each triangle was rotated in an unexpected direction.

I dug through my inventory in Second Life and found a texture I made called “mapping grid guide”. It had letters in a few cells, but not everywhere. Still, it was a start. I loaded it onto the UFO and found that only a quarter of each cell was displaying the letter.

Applying the mapping grid guide to the model

I couldn’t even make out what letters I was supposed to be looking at. Given the order of hue changing from left to right on the texture, it seemed to be going in reverse when applied to the model.

I decided to read the sculpt map from bottom to top to see if that would have any effect. Sure enough it did! I still had the same model of a UFO, but the texture was inside out. Flipping the image had the effect of reading my vertices in a clockwise direction, causing all faces to face toward the center of the model.

Looking at the inside of the UFO

I think the problem is actually with how the UV mapping is calculated instead of how vertices are read. Near the the call to update the models UV mapping, I decided to see if computeVertexNormals was still needed now that the model looked fine. Sure enough, the model still appeared, and fully intact. I removed the call (Editors Note: This was a bad idea. I had to bring it back when I noticed the directional light wasn’t hitting the model), assuming that my construction of the mesh was sufficient. Removing the call to update the UV mapping resulted in a black object that received no light. Oh well, It was worth a shot.

In my method to create a UV map, I decided to reverse the value of x to go from horizontalSegments to zero, instead of zero to horizontalSegments. It seemed to have gotten the correct orientation for the texture moving from left to right. It just feels dirty, like I’m doing something overtly wrong just to get it to work. For now, let’s put this on the back burner. I need a better texture for mapping alignment. Something with more cells.

UV alignment on quarter of quads

Before moving onto a better texture for mapping, I decided to look at a smaller sculptured prim image. The current one was 128×128 and I figured the center vertices may have a role in why nothing is appearing outside of the first quadrant. Sure enough, I could see the entire letters on geometry built with 64×64 sculpt maps.

Letters on the square cap

The fact that a vertex was still in the center of the letters cell on a smaller image confused me. The UFO had 64 segments, where the square cap had only 32. Where were the extra vertices coming from?

Time to create a useful alignment map. I did a lot of different tweaks to the new alignment maps to help identify various aspects of what may actually be happening. I generated several alignment maps in memory based on the height and width chosen. I discovered that low resolution maps were chopped up pretty bad, and the higher resolutions enabled me to get more details.

256×256 alignment map

To create the maps, I started adding the basic hue gradient horizontally, and then added another gradient vertically from gray to transparent to remove the saturation. I divided the cells with lines at every 32 pixels. I shaded every other column to be a bit darker. Since I was having an issue with only part of quadrants showing up, I added a circle within each cell to help determine if the wrong quad from another cell is taking its place. I added some letter/number coordinates over each cell. For good measure, I cycled between various colors for the circles and text. I started out with a checkerboard pattern, but then I realized that I may need more than two colors to spot the difference. Finally, I added a cross hair over the entire image to help determine where the center of the image was at when displayed on the model.

Alignment Map 256
Alignment Map 512
Alignment Map 1024
Alignment Map 2048

As I tried out different sizes, the texture was mapped onto the model clearly, and without a chopped up appearance. Once I got to size 2048, the full circles appeared and were crisp. Zooming in, I could see the coordinates were skipping rows and columns for each cell. AV30 had AX30 on its right instead of AW30. Below it was AV32 instead of AV31.

Skipping Cells

Where did these cells go? Why are lower texture resolutions so choppy on 128×128 sculpted prims? Why do lower texture resolutions work better with 64×64 sculpted prims?

One thing to note is that a 128×128 sculpted prim has 64 segments both vertically and horizontally. The 2048 texture map results in 64 cells in each column and row. The little squares representing the vertices sat perfectly on the corners of each cell in the texture map.

Looking at different models, the lowest resolution map looked just fine on the fishbowl of 64×64.

Fish Bowl with 256 alignment map

Perhaps I’m missing something. I’m scratching my head over these missing faces on larger sculpt maps. However, then I found another large sculpted prim that displayed the low resolution alignment map just fine.

Fish with 256 alignment map

Perhaps its the alignment of vertices themselves. I believe the fish was made with Second Plopp. I draw a picture of a fish. It created a puffy sculpt map and a texture that could be applied to all sides. The UFO was probably made with Rokuro. Pie sculpt 1.1 – which was also created with Rokuro, also exhibits the behavior of skipping every other cell in the texture. Trophy handles 2 is 128×128 also, but looks to be more of an extrusion, and the normals appear to be flipped.

It’s late and I need some rest. The following video is a recap of todays progress.

Mapping textures to sculpted prims on a web page.

Leave a comment

Design a site like this with WordPress.com
Get started