Many of my goals were completed yesterday in editing a vector on a model. I’ve done it via input controls. The last part of the puzzle is to edit the point on the rendered scene with the pointer. I can already select points on the model with the mouse. With this, I need to display something in the scene that the user sees to represent the xyz axis that they can move the point along.
Before that, I found a bug at the end of the day when editing models that are not built from images with the dimensions of 64×64. The x/y coordinates of the mouse were not translated properly.

And last, I had another idea about my approach to NURBS. Perhaps the models are at the 2nd degree at minimum, where the first and last point are doubled up, so that a model with 32+1 spans would have 35 knots like so:
[0, 0, 1, 2, ... 30, 31, 32, 32]
Let’s fix the easiest problem with the image coordinates. We need to pull the pointer x/y coordinates, find out where they were clicked relative to the canvas (with a border), and scale them to the original image dimensions.
function translatePointerCoordinates({clientX, clientY}, canvas, image) {
const border = 1;
const rect = canvas.getBoundingClientRect();
const x = (clientX - (rect.left + border));
const y = (clientY - (rect.top + border));
const scaleX = image.width / (rect.width - (border * 2));
const scaleY = image.height / (rect.height - (border * 2));;
return {
x: x * scaleX,
y: y * scaleY
};
}
It’s a good thing this bug popped up, as it revealed that I wasn’t taking the border into account when doing my original translations on 64×64 images.
While I was at it, I noticed that the position vector wasn’t displayed beside the title. I wired it up to display the actual position of the vertex. The raw numbers had plenty of precision and wouldn’t work. I tried to reduce it to two decimal places, but when incrementing the x/y/z values by one, sometimes the position would remain the same. The minimum precision needed was 3 decimal places. Moving the sliders to the center, it displayed 0.002 or -0.002. We’ve already honed on this earlier when doing the original translation of pixel values to vectors, but now it’s revealing itself in the UI.

Thats out of the way now. Should I try my theory on NURBS, or move onto the editing the point. I’m not sure if I’m just beating around the bush, but the NURBS theory is a bit of low hanging fruit in testing if it will work or not.
What a workout. My model appears to be more stable when changing the degrees. The models have problems connecting at the seams. As an added feature, I’m displaying the knot count in the UI and a tooltip that lists all of the knot values. I’m still unable to load models using 8×128 control nets.


The texture is off as more degrees are added. I suspect the UV mapping needs to be customized to ignore the control points used to close the loops (the hidden seam).
Well… what do you know? I got my pie table loaded with NURBS. Other models without 1:1 ratio images appear to load without errors. I was having a problem with the control net where I had flipped the rows and columns. That explains why only the square nets were loading. The main issues with NURBS is that the edges don’t line up with each other, and the texture for the first and last columns of the net is off.

I’ve been doing a few things.
I learned about the Axes helper and added it to the scene. It’s three lines that go in the xyz directions. The colors along each axis is standard. X is Red, Y is Green, and Z is blue. From the way they spell axes – I think I’ve been spelling it wrong all along. Nope… well, maybe. Axes is plural for axis.

I’m still confused over why the RGB values in the image data don’t map to XYZ in the order that they come in. Well, since there are particular colors associated with each axis, let’s see if the pixel channels match the axis colors… nope!
| Axis | Axis Color | Color Channel | Image Data |
|---|---|---|---|
| X | Red | Green | 1 |
| Y | Green | Blue | 2 |
| Z | Blue | Red | 0 |
I also added the camera controls and 3D canvas to the flex box. The area to the right of the canvas is now displaying a few groups. I also added a dark blue color as the background of the scene.

I also updated the ISO camera so that the reference cube fits perfectly within view at that angle.

I’ve been getting hung up on emissive materials. I want to see my reference cube, regardless if there is ambient light or not. I changed it to use MeshStandardMaterial and passed in the color white as the emissive setting. I even set the intensity.
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshStandardMaterial(
{ emissive: 0xFFFFFF }
);
cubeObject = new THREE.Mesh(geometry, material);
cubeObject.emissive = new THREE.Color(0xFFFFFF);
cubeObject.emissiveIntensity = 1;
Without ambient light, this cube is dark. Emissivity works in the Three.js examples that I’ve seen, so it can’t be my graphics card. Well … would you look at that. I removed the assignment of texture maps and its emissive. Maybe I need to apply them as emissive maps. Yep.
return new THREE.MeshStandardMaterial(
{ map, emissive: 0xffffff, emissiveMap: map }
);


I was adding materials to each face after the object was created, so anything I was doing to the initial material was pointless.
cubeObject.material = [ 'Right', 'Left', 'Top', 'Bottom', 'Front', 'Back' ].map(textMaterial);
From there, I added an emissive boundary cube that was textured with a grid inside-out so that it can be seen behind the model. With an emissive background, the UFO seems a to have a bit more depth and feels very dark with the current lighting. I setup each side with the color of the axis, and updated the reference cube to have the same colors matching the xyz axes.


With a boundary cube, I was able to start looking at a few models and noticed that many did not take up the full size of the space available. This means that when you create a 1x1x1 in Second Life, the sculpted objects are smaller. I’d like to scale some of these items up to take advantage of the full space available.

Well, I’ve been pulling my hair out fighting with changing the models texture to be emissive via checkbox. Toggling the texture on and off was a pain. The answer was simple, but not obvious. When you create a new material, you can set the emissive color with a number like 0xFFFFFF (which is in most examples), or a string of white. Assigning either of those values to an existing material would cause it to be completely black. The answer is to construct a Color object to be assigned.
// Works
const material = new THREE.MeshStandardMaterial( {
color: 'white',
emissive: 'white'
});
// Works
const material = new THREE.MeshStandardMaterial( {
color: 0xFFFFFF,
emissive: 0xFFFFFF
});
// Error
object.material.emissive = isEmissive ? 0xFFFFFF : 0x000000;
// Error
object.material.emissive = isEmissive ? 'white' : 'black';
// Works
object.material.emissive = new THREE.Color(
isEmissive ? 0xFFFFFF : 0x000000
);

We now have another feature that I’m familiar with in the Second Life client.
And now its bothering me that I can’t see inside the reference cube to see what direction of my model lines up with each side. Transparency was easy.

What next? You could adjust the objects opacity in Second Life as well. We can wire that up as well.

I think I’ve had enough with experimenting. The next thing you know, I’ll be adding a glow, bump mapping, or reflection.
Lets see if the threejs library has examples of editing things in the rendered space.
- animation / skinning / ik – has a set of axes that can be moved with the mouse
- shadowmap / progressive – has two axes that can be moved with the mouse
- xr / controls / transform – probably the simplest scene so far with an axes. Has additional controls to move along two axis with your mouse.
- controls / transform – even simpler. One cube. Keyboard commands let you change controls to rotate, scale, etc. Code on GitHub
Hmm… There is GridHelper and TransformControls. It looks like the GridHelper makes a 2 dimensional grid. I’ve already done that with textures… The TransformControls is the magic stuff. I just checked the example running and noticed the camera doesn’t orbit while you are using the transform controls. Great stuff. No need to switch between tools. Ack! And I see how they pulled it off. They just disable the orbit controls. I’m here destroying the controls and adding them back to the scene.
I’m not seeing the controls. I’ve tried wiring up keyboard events to change it to rotation and scale. It looks like it feeds off of the current camera, so I’m going to see if I had destroyed the initial camera it was bound to. Yep! That was it!

The controls are tiny. As I zoom in with the camera, the movement controls remain as the same size. Time to read the official documentation on TransformControls. Nothing appears for changing how thick the lines are. Found it. Setting the size on the controls works.
transformControls.setSize(transformControls.size * 3);

Well, we’ve got some problems. The transform controls doesn’t know about our constraints. We can not go out of the bounding cube. We need to clamp the scale, and make sure the object isn’t moved outside of the cube. In addition to that, we need to re-evaluate all of the vertex positions and update the sculpted prim image accordingly.
Before we do that, let’s bind the controls onto our individual vertex to adjust its position and clamp it down within the bounding box. That seems a bit simpler. Before doing that, I tweaked the controls so that I could use the toolbox to choose between move/rotate/scale. When I changed back to camera or selection tool, I had a few issues removing the controls. It’s all about cleanup, disposal, and enabling controls. I also added a method to handle to call when an object needs to be wired up.
The problem I’m running into is with the rotation. I can see the rotation overlay. When I drag my mouse in the middle, I see an axis moving about – but no rotation. I can click between move & scale and see that they are changing the object.
So I figured it out. It all has to do with my original spin controls. With every render, I’m rotating the object if the spin is enabled, and updating accordingly. I didn’t wire up the rotation inputs to change the object when they change. Instead, I’m reading them on every animation frame and applying their values to the object. Ugh! Sloppy. I need to fix that.
Now I have a problem. When I move the model with the transformation controls, changing a pixels xyz coordinates snaps the model back to the center of the grid. I need to save the models position, scale, and rotation before it is rebuilt, and re-apply them.
That was fun. I updated all models and UI as the edits took place. I can change between different models, and the same transformations are in effect.
Lets see what we can do to clamp down the model into the 1x1x1 bounding box. After that, I can start baking the updated vector positions into the original sculpted prim image.
I’m about to head to bed.
One final thing before I head off. High memory usage. I just noticed I can hover over my web browsers tabs and see memory usage. For most tabs, I’m seeing numbers mostly under 200 MB. My web page uses 1.3 GB. I’m curious as to what its from. NURBS? Maybe its due to the fact that I have a lot of cubes representing each vertex.

Odd. A new browser tab had it at 50 MB. Playing around with various features, I was able to get it up to 131MB. There may be a memory leak somewhere.
