2

Each face has 3 colors (one for each vertex). I want to use Gouraud shading to blend these colors. So far, I have taken some inspiration from the FXyz library.

My current approach uses the setTextureModeVertices3D from the FXyz library. But this uses density maps, which does not work in my case because the colors don't come from a mathematical formula. My initial idea was to implement it as follows:

  1. Calculate the color for each vertex in the mesh.
  2. Extract a list of all the unique colors
  3. Make a palette of the unique colors
        val palette = object : ColorPalette {
            override fun getNumColors() = colors.size
            override fun getColor(i: Int) = colors.getOrNull(i)?: Color.BLACK
        }
  1. Make a map with as key the point value (x,y,z) and with as value the index of the color
  2. Make a density function that returns the color index from the aforementioned map.
        { point3F ->
            val key = Triple(point3F.x.toInt(), point3F.y.toInt(), point3F.z.toInt())
            pointColorIndexMap[key]!!
        }

I have a feeling my only option is to create one large image where I put in all shaded triangles, and then references those. But I am unsure what the best technique would be here. Any help is appreciated!

Edit:

This is the code I currently use (this is written in Kotlin):

override fun updateMesh() {
    val definition = model.modelDefinition

    val (colors1, colors2, colors3) = definition.calculateFaceColors()
    val uniqueColorHSBValues = (colors1 + colors2 + colors3).toSet().toList()
    val uniqueColors = uniqueColorHSBValues.map { ModelUtil.hsbToColor(it, null) }

    val palette = object : ColorPalette {
        override fun getNumColors() = uniqueColors.size
        override fun getColor(i: Int) = uniqueColors.getOrNull(i)?: Color.BLACK
    }

    val pointColorIndexMap = HashMap<Triple<Int, Int, Int>, Int>()
    for (face in 0 until definition.getFaceCount()) {
        val type = definition.getFaceTypes()?.get(face)?.toInt()?.let { it and 3}?:0
        val (p1, p2, p3) = definition.getPoints(face)
        if (type == RENDER_SHADED_TRIANGLE) {
            pointColorIndexMap[p1] = uniqueColorHSBValues.indexOf(colors1[face])
            pointColorIndexMap[p2] = uniqueColorHSBValues.indexOf(colors2[face])
            pointColorIndexMap[p3] = uniqueColorHSBValues.indexOf(colors3[face])
        } else if (type == RENDER_FLAT_TRIANGLE) {
            pointColorIndexMap[p1] = uniqueColorHSBValues.indexOf(colors1[face])
            pointColorIndexMap[p2] = uniqueColorHSBValues.indexOf(colors1[face])
            pointColorIndexMap[p3] = uniqueColorHSBValues.indexOf(colors1[face])
        }
    }

    setTextureModeVertices3D(palette) { point3F ->
        val key = Triple(point3F.x.toInt(), point3F.y.toInt(), point3F.z.toInt())
        pointColorIndexMap[key]!!
    }

    val meshHelper = MeshHelper(atlas)
    updateMesh(meshHelper)
}
  • This is how my current implementation of the shading looks like. How my implementation currently is with shading
  • This is how my current implementation looks like without the shading. How my implementation currently is without shading
  • This is how I want my implementation of the shading to roughly look like How I want my implementation with shading to look like roughly
  • This is how my palette looks like (9x10 pixels) (enter image description here
  • 1
    How do you plan to calculate the color for each vertex? Isn't there an algorithm for it? That would be your "density map" function (once you have the color for each vertex, the interpolation for the triangle is already linear). – José Pereda May 17 '21 at 08:27
  • Hey @JoséPereda I derive the calculations from a java 3d game client that implements scan line rendering. I updated my thread with some examples, maybe that clarifies the issue better than I can in words. I think maybe my issue is that I don't deal with face render prioritisation. – Stan van der Bend May 17 '21 at 08:45
  • 1
    If I get it right, you have a palette of colors and you know the color that should be applied to each vertex (based on external tools). Now you could use [setTextureModeVertices3D](https://github.com/FXyz/FXyz/blob/master/FXyz-Core/src/main/java/org/fxyz3d/shapes/primitives/TexturedMesh.java#L190), and you could pass an "f" value to each [Point3D](https://github.com/FXyz/FXyz/blob/master/FXyz-Core/src/main/java/org/fxyz3d/geometry/Point3D.java#L60) when you define the mesh, based on the index of the color, and then your density function will be just `p -> p.f`. – José Pereda May 17 '21 at 09:00
  • @JoséPereda Yes that is right, this is essentially what I am doing at the moment. But instead of using `p.f` I has a map that returns the value of `f` (the color index in the palette) where the key are the `x,y,z`values of `p`. Which produces the results included in the post. – Stan van der Bend May 17 '21 at 09:56
  • I have updated my post with the code I use – Stan van der Bend May 17 '21 at 10:04
  • 1
    Not sure if I follow completely, but you do the same for Shaded and Flat triangle. Also, if you get the int part of your coordinates as key, you might miss many values? – José Pereda May 17 '21 at 10:18
  • @JoséPereda It's not the same, the flat one only uses `colors1`. And no all the coordinates are integer valued but converted to floats only for the sake of API usage. – Stan van der Bend May 17 '21 at 10:27
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/232508/discussion-between-stan-van-der-bend-and-jose-pereda). – Stan van der Bend May 17 '21 at 10:32

0 Answers0