Skip to content

Commit

Permalink
[orx-mesh-noise] Add generated and verified documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
edwinRNDR committed Jan 18, 2025
1 parent 5daa91b commit ff59bab
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 8 deletions.
90 changes: 83 additions & 7 deletions orx-mesh-noise/src/commonMain/kotlin/MeshNoise.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,22 @@ fun uniformBarycentric(random: Random = Random.Default): Vector3 {
return Vector3(b0, b1, 1.0 - b0 - b1)
}

/**
* Generate a non-uniformly distributed barycentric coordinate
* @param random a random number generator
*/
fun nonUniformBarycentric(weight0: Double, weight1: Double, weight2: Double, random: Random = Random.Default): Vector3 {
val b = uniformBarycentric()
var b0 = b.x / weight0
var b1 = b.y / weight1
var b2 = b.z / weight2
val totalWeight = b0 + b1 + b2
b0 /= totalWeight
b1 /= totalWeight
b2 /= totalWeight
return Vector3(b0, b1, b2)
}

/**
* Generate a uniformly distributed barycentric coordinate
* @param random a random number generator
Expand All @@ -32,7 +48,6 @@ fun hashBarycentric(seed: Int, x: Int): Vector3 {
val v = fhash1D(seed, u.toRawBits().toInt() - x)



val su0 = sqrt(u)
val b0 = 1.0 - su0
val b1 = v * su0
Expand All @@ -46,36 +61,97 @@ fun hashBarycentric(seed: Int, x: Int): Vector3 {
* @param random a random number generator
*/
fun IIndexedPolygon.uniform(vertexData: IVertexData, random: Random = Random.Default): Vector3 {
require(positions.size == 3) { "polygon must be a triangle"}
require(positions.size == 3) { "polygon must be a triangle" }

val x = vertexData.positions.slice(positions)
val b = uniformBarycentric(random)
return x[0] * b.x + x[1] * b.y + x[2] * b.z
}

/**
* Computes a point within a triangle defined by the current indexed polygon. The point is determined
* through non-uniform barycentric coordinates, which are influenced by the specified weights.
*
* @param vertexData the vertex data containing positions and other attributes
* @param weight0 the weight associated with the first vertex of the triangle
* @param weight1 the weight associated with the second vertex of the triangle
* @param weight2 the weight associated with the third vertex of the triangle
* @param random an optional random number generator used for generating the barycentric coordinates
* @return a 3D vector representing a point within the triangle specified by the barycentric coordinates
*/
fun IIndexedPolygon.nonUniform(
vertexData: IVertexData,
weight0: Double,
weight1: Double,
weight2: Double,
random: Random = Random.Default
): Vector3 {
require(positions.size == 3) { "polygon must be a triangle" }

val x = vertexData.positions.slice(positions)
val b = nonUniformBarycentric(weight0, weight1, weight2, random)
return x[0] * b.x + x[1] * b.y + x[2] * b.z
}

/**
* Generate a uniformly distributed point that lies inside this [IIndexedPolygon]
* @param vertexData vertex data used to resolve positions
* @param random a random number generator
*/
fun IIndexedPolygon.hash(vertexData: IVertexData, seed:Int, x: Int): Vector3 {
require(positions.size == 3) { "polygon must be a triangle"}
fun IIndexedPolygon.hash(vertexData: IVertexData, seed: Int, x: Int): Vector3 {
require(positions.size == 3) { "polygon must be a triangle" }

val s = vertexData.positions.slice(positions)
val b = hashBarycentric(seed, x)
return s[0] * b.x + s[1] * b.y + s[2] * b.z
}

/**
* Calculates the area of the triangular polygon.
*
* The method assumes that the polygon is a triangle and computes its area
* using the cross product formula. The computed area is a positive value as it
* represents the absolute area of the triangle.
*
* @param vertexData the vertex data containing positional information of the polygon vertices
* @return the area of the triangle as a Double
* @throws IllegalArgumentException if the polygon is not a triangle (i.e., does not have exactly 3 vertices)
*/
internal fun IIndexedPolygon.area(vertexData: IVertexData): Double {
require(positions.size == 3) { "polygon must be a triangle"}
require(positions.size == 3) { "polygon must be a triangle" }
val x = vertexData.positions.slice(positions)
val u = x[1] - x[0]
val v = x[2] - x[0]
return u.areaBetween(v) / 2.0
}

/**
* Generate points on the surface described by the mesh data
* Computes the weighted area of a triangular polygon by scaling its area with the average of the given weights.
*
* @param vertexData the vertex data containing position information of the polygon vertices
* @param weight0 the weight associated with the first vertex of the polygon
* @param weight1 the weight associated with the second vertex of the polygon
* @param weight2 the weight associated with the third vertex of the polygon
* @return the weighted area of the triangular polygon
*/
internal fun IIndexedPolygon.weightedArea(
vertexData: IVertexData,
weight0: Double,
weight1: Double,
weight2: Double
): Double {
return area(vertexData) * (weight0 + weight1 + weight2) / 3.0
}

/**
* Generates a list of uniformly distributed points on the surface of the given mesh.
*
* The method uses triangulation and computes areas of triangular polygons to ensure
* uniform distribution of points across the surface.
*
* @param count the number of points to generate
* @param random a random number generator instance, defaulting to [Random.Default]
* @return a list of [Vector3] points uniformly distributed across the mesh surface
*/
fun IMeshData.uniform(count: Int, random: Random = Random.Default): List<Vector3> {
val triangulated = triangulate()
Expand All @@ -100,7 +176,7 @@ fun IMeshData.uniform(count: Int, random: Random = Random.Default): List<Vector3
/**
* Generate points on the surface described by the mesh data
*/
fun IMeshData.hash(count: Int, seed:Int, x: Int): List<Vector3> {
fun IMeshData.hash(count: Int, seed: Int, x: Int): List<Vector3> {
val triangulated = triangulate()
val result = mutableListOf<Vector3>()
val totalArea = triangulated.polygons.sumOf { it.area(vertexData) }
Expand Down
15 changes: 14 additions & 1 deletion orx-mesh-noise/src/jvmDemo/kotlin/DemoMeshNoise01.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,21 @@ import org.openrndr.math.Vector3
import java.io.File
import kotlin.random.Random


/**
* Demonstrate uniform point on mesh generation
* This demo creates a 3D visualization program using the OPENRNDR framework.
* It demonstrates loading an OBJ model, generating uniform points on the surface
* of the mesh, and rendering these points as small spheres using a custom shader.
*
* The following key processes are performed:
* - Loading mesh data from an OBJ file.
* - Generating a list of uniformly distributed points on the mesh surface.
* - Rendering the generated points with small spheres.
* - Using an "Orbital" extension for interactive camera control.
* - Applying a shader effect to visualize surface normals.
*
* The application runs with a window size of 720x720 pixels and positions the camera
* in front of the scene using the "Orbital" extension.
*/
fun main() {
application {
Expand Down

0 comments on commit ff59bab

Please sign in to comment.