View Full Version : how to check bitmap uv coords?

 stuh50510 October 2005, 01:02 AMI realize this is going to sound insane, but... how can I write a function to sum up the pixel values of all the pixels on a texture map that are within the UV coordinates of a specified face on the object (edit poly or mesh, whichever is easier)? edit -- hold on, i might have it. ill post back if i have further troubles
stuh505
10 October 2005, 01:25 AM
ok...it seems this will help:

theFace = meshop.getMapFace theMesh theChannel faceIndex

vert1= meshop.getMapVert theMesh theChannel theFace.x

vert2= meshop.getMapVert theMesh theChannel theFace.y

vert3= meshop.getMapVert theMesh theChannel theFace.z

Bobo
10 October 2005, 02:46 AM
ok...it seems this will help:

theFace = meshop.getMapFace theMesh theChannel faceIndex

vert1= meshop.getMapVert theMesh theChannel theFace.x

vert2= meshop.getMapVert theMesh theChannel theFace.y

vert3= meshop.getMapVert theMesh theChannel theFace.z

This gives you the UVW coordinates of the 3 vertices, NOT the pixel values.
You might have to take the min. and max. of these 3 values and convert them into texel values, giving you a rectangle of pixels that potentially are within the face, then go through all these pixels, calcluate their corresponding UV coordinates and see whether they are inside the triangle or outside (possibly by modifying the barycentric coordinates code shown in http://forums.cgsociety.org/showthread.php?t=275372)

Bobo
10 October 2005, 02:48 AM
This gives you the UVW coordinates of the 3 vertices, NOT the pixel values.
You might have to take the min. and max. of these 3 values and convert them into texel values, giving you a rectangle of pixels that potentially are within the face, then go through all these pixels, calcluate their corresponding UV coordinates and see whether they are inside the triangle or outside (possibly by modifying the barycentric coordinates code shown in http://forums.cgsociety.org/showthread.php?t=275372)

Actually, it would be easier to calculate the pixels that are on the edges of the triangle (similar to drawing a triangle between the 3 pixels corresponding to the vertices) and then collect all pixel values between these edge pixel coordinates one scanline at a time...

stuh505
10 October 2005, 03:31 PM
Actually, it would be easier to calculate the pixels that are on the edges of the triangle (similar to drawing a triangle between the 3 pixels corresponding to the vertices) and then collect all pixel values between these edge pixel coordinates one scanline at a time...

Yeah, this is what I came up with also. That's got to be the best way to do it if there aren't any built in functions. It's still going to be a pain though :P If I get it working I'll post the function just in case anyone else finds themself wanting this information in the future.

stuh505
10 October 2005, 05:01 PM
getPixels is used to get a row from a bitmap. it says that the row is the y coordinate. usually the x/y coordinates start at 0 in the lower left corner, and the row/col coordinates start at 0 in the upper left corner. does this mean that if i specify row zero, i will get the bottom row of pixels from the image?

Bobo
10 October 2005, 06:23 PM
getPixels is used to get a row from a bitmap. it says that the row is the y coordinate. usually the x/y coordinates start at 0 in the lower left corner, and the row/col coordinates start at 0 in the upper left corner. does this mean that if i specify row zero, i will get the bottom row of pixels from the image?

Nope, while the UVs have origin at bottom left, bitmaps have their origin at upper left. So you just flip the Y axis.

Getting row 0 will give you the top row of pixels, getting row Height-1 will give you the bottom row of pixels. Just take the resulting pixel's Y value and subtract from the (height of the map - 1) to get the actual value.
For example, if the height of the map H = 512, V = 0, then Y = 0 and it should be (H-1)-V = (512-1)-0 = 511.

In addition, you can get a subrow of pixels starting at X > 0 and getting a number of pixels less than the rest of the row to get just a small part of the row.

I would collect all rows between the min. and max. values in a 2D array (array of arrays) first using getPixels, then "draw" the borders inside the array by changing the colors to some special name value for each edge, and then collect all values in each row that are between these special edge values...

Cheers,
Bobo

stuh505
10 October 2005, 02:27 AM
Thanks Bobo.

I did it differently. I calculated the equations of the lines between each vertex, and then used the getPixels function to go through and incrementally get each row of pixels. In order to determine the starting and ending pixels of each row that were within the triangle, I solved the equations of the edge lines for the current row value.

This took me only a few minutes to code up...but working out for all the special cases took me about...4 hours. Ugh. There are special cases because of vertical lines, horizontal lines, different ordering of vertices, etc.

Well, I think I've got it working now.

EDIT: verified, it works...and it's VERY fast!! this func takes only 0.000369 seconds to execute...I was expecting something closer to 3-4 seconds

This function simply returns the sum of the intensity/value of each pixel of the map that is in the diffuse color slot for a specified face of a specified mesh.

struct mline
(
slope, -- negative 1 means vertical, and intercept is for x not y
intercept
)
function sumFaceTexturePixels tmesh face=
(
if (face < 0 or face > tmesh.numfaces) then
(
messagebox ("sumFaceTexturePixels: face index out of bounds (" + (face as string) + ")")
return -1;
)
function getSlope a b coords =
(
if (coords[a].x == coords[b].x) then
return -1 --slope is infinite, vertical line
else
return ((coords[a].y - coords[b].y) / (coords[a].x - coords[b].x))
)

function getIntercept a b slope coords =
(
if (coords[a].x == coords[b].x) then
return coords[a].x --no Y intercept, so give X intercept instead...
else
return (coords[a].y - (slope * coords[a].x))
)

--returns the x coord of the line at the y coord
--note: if its a vertical line, the line intercepts the X axis at intercept
-- otherwise, intercept is the Y intercept
function interceptLine y line =
(

if (line.slope == -1) then
return line.intercept
else
return (y - line.intercept) / line.slope
)

--get the bmp
tbmp = (getSubTexMap tmesh.material 2).bitmap

--gets the indices of the 3 verts using this face
theFace = meshop.getMapFace tmesh 1 face

--gets the UV coordinates of each vert
uvCoords = #()
append uvCoords (meshop.getMapVert tmesh 1 theFace.x)
append uvCoords (meshop.getMapVert tmesh 1 theFace.y)
append uvCoords (meshop.getMapVert tmesh 1 theFace.z)

--convert the UV coords to absolute bmp coords
bmpCoords = #()

for i = 1 to uvCoords.count do
append bmpCoords [uvCoords[i].x * tbmp.width, uvCoords[i].y * tbmp.height]

--calculate the left/middle/and right verts of the face triangle
topVert = 1
for i = 2 to uvCoords.count do
(
if uvCoords[i].y > uvCoords[topVert].y then
topVert = i
)

bottomVert = 1
for i = 2 to uvCoords.count do
(
if uvCoords[i].y < uvCoords[bottomVert].y then
bottomVert = i
)

middleVert = 1
for i = 2 to uvCoords.count do
(
if topVert == middleVert or bottomVert == middleVert then
middleVert = middleVert + 1
)

--perform necessary swaps in order to know which line EQs to use...

if ((bmpCoords[topVert].y == bmpCoords[middleVert].y) and (bmpCoords[topVert].x > bmpCoords[middleVert].x)) then
(
temp = topVert
topVert = middleVert
middleVert = temp
)

if ((bmpCoords[bottomVert].y == bmpCoords[middleVert].y) and (bmpCoords[bottomVert].x > bmpCoords[middleVert].x)) then
(
temp = bottomVert
bottomVert = middleVert
middleVert = temp
)

--ASSERT: if bottom.y == middle.y, then bottom.x < middle.x
--ASSERT: if top.y == middle.y, then top.x < middle.x
edgeLines = #()

--edgeLines[1] = line from top to bottom vert
aslope = (getSlope topVert bottomVert bmpCoords)
aintercept = (getIntercept topVert bottomVert aslope bmpCoords)
aline = mline slope: aslope intercept: aintercept

append edgeLines aline

--edgeLines[2] = line from top to middle vert
aslope = (getSlope topVert middleVert bmpCoords)
aintercept = (getIntercept topVert middleVert aslope bmpCoords)
aline = mline slope: aslope intercept: aintercept
append edgeLines aline

--edgeLines[3] = line from middle to bottom vert
aslope = (getSlope middleVert bottomVert bmpCoords)
aintercept = (getIntercept middleVert bottomVert aslope bmpCoords)
aline = mline slope: aslope intercept: aintercept
append edgeLines aline

--determine which equations should be used to bound the column start/ends of each row strip
leftEQ = 1
rightEQ = 2
changeof = true --will switch equations after passing mid-vertex

if (bmpCoords[bottomVert].y == bmpCoords[middleVert].y) then
(
leftEQ = 1
rightEQ = 2
changeof = false
)

if (bmpCoords[topVert].y == bmpCoords[middleVert].y) then
(
leftEQ = 1
rightEQ = 3
changeof = false
)

pixelArray = #()
row = bmpCoords[topVert].y
rowscounted = 0

while (row > bmpCoords[bottomVert].y) do
(
--switch equations after passing the middle vert if need be
if (changeof and row > bmpCoords[middleVert].y) then
rightEQ = 3

startcol = (interceptLine row edgeLines[leftEQ] )
endcol = (interceptLine row edgeLines[rightEQ] )

if (startcol > endcol) then
(
temp = startcol
startcol = endcol
endcol = temp
)

--grab the row strip of pixels
newRow = getPixels tbmp [startcol, (tbmp.height - row)] (endcol - startcol)

pixelArray = pixelArray + newRow
row = row - 1
rowscounted = rowscounted + 1

--messageBox (startcol as string + " " + endcol as string)
)
pixelSum = 0
for i = 1 to pixelArray.count do
pixelSum = pixelSum + pixelArray[i].value

if (pixelArray.count > 0) then
pixelAvg = pixelSum / pixelArray.count
else
pixelAvg = 0

return pixelAvg
)

Bobo
10 October 2005, 06:40 PM
Well, I think I've got it working now.

EDIT: verified, it works...and it's VERY fast!! this func takes only 0.000369 seconds to execute...I was expecting something closer to 3-4 seconds

This function simply returns the sum of the intensity/value of each pixel of the map that is in the diffuse color slot for a specified face of a specified mesh.

Fantastic, glad it worked in the end!

Cheers,
Bobo

CGTalk Moderation
10 October 2005, 06:40 PM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.

1