-
Notifications
You must be signed in to change notification settings - Fork 37
/
DemoExtrude06.kt
130 lines (113 loc) · 4.57 KB
/
DemoExtrude06.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import org.openrndr.WindowMultisample
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.draw.*
import org.openrndr.extra.camera.Orbital
import org.openrndr.extra.meshgenerators.buildTriangleMesh
import org.openrndr.extra.meshgenerators.extrudeContourStepsMorphed
import org.openrndr.extra.noise.Random
import org.openrndr.extra.noise.simplex
import org.openrndr.math.Polar
import org.openrndr.math.Vector2
import org.openrndr.math.Vector3
import org.openrndr.math.transforms.transform
import org.openrndr.shape.Circle
import org.openrndr.shape.Path3D
import org.openrndr.shape.Segment3D
import kotlin.math.PI
import kotlin.math.cos
/**
* Demo extrudeContourStepsMorphed which allows to create a mesh with a morphing cross-section
* based on the t value along a Path3D. In other words, a tube in which the cross-section does not need
* to be constant, but can be scaled, rotated and displaced along its curvy axis.
*/
fun main() {
application {
configure {
width = 800
height = 800
multisample = WindowMultisample.SampleCount(8)
}
program {
Random.seed = System.currentTimeMillis().toString()
val texture = loadImage("demo-data/images/peopleCity01.jpg").also {
it.wrapU = WrapMode.REPEAT
it.wrapV = WrapMode.REPEAT
it.filterMag = MagnifyingFilter.LINEAR
it.filterMin = MinifyingFilter.LINEAR
}
val shader = shadeStyle {
fragmentTransform = """
// A. Passed color
x_fill = va_color;
// B. Sample texture
//x_fill = texture(p_img, va_texCoord0.yx * vec2(20.0, 1.0));
// Show (add) UV coords
x_fill.rb += va_texCoord0.yx;
// Vertical lighting
x_fill.rgb *= dot(vec3(0.0, 1.0, 0.0), v_viewNormal.xyz) * 0.3 + 0.7;
// Black fog (darken far away shapes)
x_fill.rgb += v_viewPosition.z * 0.05;
""".trimIndent()
parameter("img", texture)
}
extend(Orbital()) {
eye = Vector3(0.0, 3.0, 7.0)
lookAt = Vector3(0.0, 0.0, 0.0)
}
extend {
drawer.stroke = null
val path = get3DPath(10.0, seconds * 0.05, 400)
val tubes = makeTubes(path, seconds * 0.2)
shader.parameter("seconds", seconds * 0.1)
drawer.fill = ColorRGBa.WHITE
drawer.shadeStyle = shader
tubes.forEachIndexed { i, vb ->
shader.parameter("offset", i * 0.3 + 0.2)
// Mirror the mesh 5 times
repeat(5) {
drawer.isolated {
rotate(Vector3.UNIT_Z, it * 72.0)
vertexBuffer(vb, DrawPrimitive.TRIANGLES)
}
}
// Remember to free the memory! Otherwise, the computer will quickly run out of RAM.
vb.destroy()
}
}
}
}
}
val crossSection = Circle(Vector2.ZERO, 0.1).contour.transform(
transform { scale(5.0, 1.0, 1.0) }
)
// Create simplex-based 3D path
fun get3DPath(scale: Double, time: Double, steps: Int): Path3D {
val mult = 0.005
val points = List(steps) { Vector3.simplex(337, time + it * mult) * scale }
return Path3D(points.windowed(2).map { Segment3D(it[0], it[1]) }, false)
}
// Create 3 spinning tubes around path
fun makeTubes(path: Path3D, seconds: Double) = List(3) { i ->
buildTriangleMesh {
val degrees = seconds * 60
val crossSection = crossSection
color = listOf(ColorRGBa.RED, ColorRGBa.GREEN, ColorRGBa.BLUE)[i]
extrudeContourStepsMorphed(
{ t: Double ->
val turns = t * 360 * 10
val cosEnv = 0.5 - 0.49 * cos(t * 2 * PI)
crossSection.transform(transform {
val theta = i * 120.0
translate(Polar(turns - degrees + theta, 0.6 * cosEnv).cartesian)
rotate(-turns - degrees)
scale(cosEnv)
})
},
path,
path.segments.size,
Vector3.UNIT_Y,
contourDistanceTolerance = 0.01
)
}
}