Skip to content

Commit 44044e8

Browse files
committed
Add support for color in PLY files.
1 parent 3488659 commit 44044e8

File tree

3 files changed

+87
-14
lines changed

3 files changed

+87
-14
lines changed

app/src/main/java/com/dmitrybrant/modelviewer/ply/PlyModel.kt

Lines changed: 69 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import com.dmitrybrant.modelviewer.util.Util.readIntLe
1010
import java.io.*
1111
import java.nio.ByteBuffer
1212
import java.nio.ByteOrder
13+
import java.nio.FloatBuffer
1314

1415
/*
1516
*
@@ -32,6 +33,16 @@ import java.nio.ByteOrder
3233
*/
3334
class PlyModel(inputStream: InputStream) : IndexedModel() {
3435
private val pointColor = floatArrayOf(1.0f, 1.0f, 1.0f)
36+
private var colorBuffer: FloatBuffer? = null
37+
38+
private var xIndex = -1
39+
private var yIndex = -1
40+
private var zIndex = -1
41+
private var rIndex = -1
42+
private var gIndex = -1
43+
private var bIndex = -1
44+
private var alphaIndex = -1
45+
private var haveColor = false
3546

3647
init {
3748
val stream = BufferedInputStream(inputStream, INPUT_BUFFER_SIZE)
@@ -46,7 +57,7 @@ class PlyModel(inputStream: InputStream) : IndexedModel() {
4657
GLES20.glDeleteProgram(glProgram)
4758
glProgram = -1
4859
}
49-
glProgram = compileProgram(R.raw.point_cloud_vertex, R.raw.single_color_fragment, arrayOf("a_Position"))
60+
glProgram = compileProgram(R.raw.point_cloud_vertex, R.raw.point_cloud_fragment, arrayOf("a_Position", "a_Color"))
5061
initModelMatrix(boundSize)
5162
}
5263

@@ -62,6 +73,7 @@ class PlyModel(inputStream: InputStream) : IndexedModel() {
6273

6374
private fun readText(stream: BufferedInputStream) {
6475
val vertices = mutableListOf<Float>()
76+
val colors = mutableListOf<Float>()
6577
val reader = BufferedReader(InputStreamReader(stream), INPUT_BUFFER_SIZE)
6678
var line: String
6779
var lineArr: Array<String>
@@ -74,42 +86,66 @@ class PlyModel(inputStream: InputStream) : IndexedModel() {
7486
*/
7587
stream.mark(0x100000)
7688
var isBinary = false
89+
var propIndex = 0
7790
while (reader.readLine().also { line = it.orEmpty() } != null) {
7891
line = line.trim()
92+
lineArr = line.split(" ").toTypedArray()
7993
if (line.startsWith("format ")) {
8094
if (line.contains("binary")) {
8195
isBinary = true
8296
}
8397
} else if (line.startsWith("element vertex")) {
84-
lineArr = line.split(" ".toRegex()).toTypedArray()
8598
vertexCount = lineArr[2].toInt()
99+
} else if (line.startsWith("property ")) {
100+
val propName = lineArr[lineArr.size - 1]
101+
if (propName == "x" && xIndex < 0) { xIndex = propIndex }
102+
else if (propName == "y" && yIndex < 0) { yIndex = propIndex }
103+
else if (propName == "z" && zIndex < 0) { zIndex = propIndex }
104+
else if (propName == "red" && rIndex < 0) { rIndex = propIndex }
105+
else if (propName == "green" && gIndex < 0) { gIndex = propIndex }
106+
else if (propName == "blue" && bIndex < 0) { bIndex = propIndex }
107+
else if (propName == "alpha" && alphaIndex < 0) { alphaIndex = propIndex }
108+
propIndex++
86109
} else if (line.startsWith("end_header")) {
87110
break
88111
}
89112
}
90113
if (vertexCount <= 0) {
91114
return
92115
}
116+
if (rIndex >= 0 && gIndex >= 0 && bIndex >= 0) {
117+
haveColor = true
118+
}
93119

94120
if (isBinary) {
95121
stream.reset()
96-
readVerticesBinary(vertices, stream)
122+
readVerticesBinary(vertices, colors, stream)
97123
} else {
98-
readVerticesText(vertices, reader)
124+
readVerticesText(vertices, colors, reader)
99125
}
100126

101-
val floatArray = FloatArray(vertices.size)
127+
var floatArray = FloatArray(vertices.size)
102128
for (i in vertices.indices) {
103129
floatArray[i] = vertices[i]
104130
}
105-
val vbb = ByteBuffer.allocateDirect(floatArray.size * BYTES_PER_FLOAT)
131+
var vbb = ByteBuffer.allocateDirect(floatArray.size * BYTES_PER_FLOAT)
106132
vbb.order(ByteOrder.nativeOrder())
107133
vertexBuffer = vbb.asFloatBuffer()
108134
vertexBuffer!!.put(floatArray)
109135
vertexBuffer!!.position(0)
136+
137+
floatArray = FloatArray(colors.size)
138+
for (i in colors.indices) {
139+
floatArray[i] = colors[i]
140+
}
141+
vbb = ByteBuffer.allocateDirect(floatArray.size * BYTES_PER_FLOAT)
142+
vbb.order(ByteOrder.nativeOrder())
143+
colorBuffer = vbb.asFloatBuffer()
144+
colorBuffer!!.put(floatArray)
145+
colorBuffer!!.position(0)
110146
}
111147

112-
private fun readVerticesText(vertices: MutableList<Float>, reader: BufferedReader) {
148+
private fun readVerticesText(vertices: MutableList<Float>, colors: MutableList<Float>, reader: BufferedReader) {
113149
var lineArr: Array<String>
114150
var x: Float
115151
var y: Float
@@ -119,24 +155,35 @@ class PlyModel(inputStream: InputStream) : IndexedModel() {
119155
var centerMassZ = 0.0
120156

121157
for (i in 0 until vertexCount) {
122-
lineArr = reader.readLine().trim().split(" ".toRegex()).toTypedArray()
123-
x = lineArr[0].toFloat()
124-
y = lineArr[1].toFloat()
125-
z = lineArr[2].toFloat()
158+
lineArr = reader.readLine().trim().split(" ").toTypedArray()
159+
x = lineArr[xIndex].toFloat()
160+
y = lineArr[yIndex].toFloat()
161+
z = lineArr[zIndex].toFloat()
126162
vertices.add(x)
127163
vertices.add(y)
128164
vertices.add(z)
129165
adjustMaxMin(x, y, z)
130166
centerMassX += x.toDouble()
131167
centerMassY += y.toDouble()
132168
centerMassZ += z.toDouble()
169+
if (haveColor) {
170+
colors.add(lineArr[rIndex].toFloat() / 255f)
171+
colors.add(lineArr[gIndex].toFloat() / 255f)
172+
colors.add(lineArr[bIndex].toFloat() / 255f)
173+
colors.add(if (alphaIndex >= 0) lineArr[alphaIndex].toFloat() / 255f else 1f)
174+
} else {
175+
colors.add(pointColor[0])
176+
colors.add(pointColor[1])
177+
colors.add(pointColor[2])
178+
colors.add(255f)
179+
}
133180
}
134181
this.centerMassX = (centerMassX / vertexCount).toFloat()
135182
this.centerMassY = (centerMassY / vertexCount).toFloat()
136183
this.centerMassZ = (centerMassZ / vertexCount).toFloat()
137184
}
138185

139-
private fun readVerticesBinary(vertices: MutableList<Float>, stream: BufferedInputStream) {
186+
private fun readVerticesBinary(vertices: MutableList<Float>, colors: MutableList<Float>, stream: BufferedInputStream) {
140187
val tempBytes = ByteArray(0x1000)
141188
stream.mark(1)
142189
stream.read(tempBytes)
@@ -164,6 +211,12 @@ class PlyModel(inputStream: InputStream) : IndexedModel() {
164211
centerMassX += x.toDouble()
165212
centerMassY += y.toDouble()
166213
centerMassZ += z.toDouble()
214+
215+
// TODO: extract color from binary format
216+
colors.add(pointColor[0])
217+
colors.add(pointColor[1])
218+
colors.add(pointColor[2])
219+
colors.add(255f)
167220
}
168221
this.centerMassX = (centerMassX / vertexCount).toFloat()
169222
this.centerMassY = (centerMassY / vertexCount).toFloat()
@@ -177,11 +230,13 @@ class PlyModel(inputStream: InputStream) : IndexedModel() {
177230
GLES20.glUseProgram(glProgram)
178231
val mvpMatrixHandle = GLES20.glGetUniformLocation(glProgram, "u_MVP")
179232
val positionHandle = GLES20.glGetAttribLocation(glProgram, "a_Position")
233+
val colorHandle = GLES20.glGetAttribLocation(glProgram, "a_Color")
180234
val pointThicknessHandle = GLES20.glGetUniformLocation(glProgram, "u_PointThickness")
181235
val ambientColorHandle = GLES20.glGetUniformLocation(glProgram, "u_ambientColor")
182236
GLES20.glEnableVertexAttribArray(positionHandle)
183-
GLES20.glVertexAttribPointer(positionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false,
184-
VERTEX_STRIDE, vertexBuffer)
237+
GLES20.glVertexAttribPointer(positionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, VERTEX_STRIDE, vertexBuffer)
238+
GLES20.glEnableVertexAttribArray(colorHandle)
239+
GLES20.glVertexAttribPointer(colorHandle, 4, GLES20.GL_FLOAT, false, 4 * BYTES_PER_FLOAT, colorBuffer)
185240
Matrix.multiplyMM(mvMatrix, 0, viewMatrix, 0, modelMatrix, 0)
186241
Matrix.multiplyMM(mvpMatrix, 0, projectionMatrix, 0, mvMatrix, 0)
187242
GLES20.glUniformMatrix4fv(mvpMatrixHandle, 1, false, mvpMatrix, 0)
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
precision mediump float;
2+
3+
uniform vec3 u_ambientColor;
4+
varying vec4 v_Color;
5+
6+
/*
7+
Dmitry Brant, 2021
8+
*/
9+
void main()
10+
{
11+
float maxDepth = 50.0;
12+
float depth = gl_FragCoord.z / gl_FragCoord.w;
13+
//gl_FragColor = vec4(u_ambientColor * (maxDepth / depth), 1.0);
14+
gl_FragColor = v_Color;
15+
}

app/src/main/res/raw/point_cloud_vertex.glsl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
precision mediump float;
22

33
attribute vec4 a_Position;
4+
attribute vec4 a_Color;
5+
varying vec4 v_Color;
46
uniform mat4 u_MVP;
57
uniform float u_PointThickness;
68

@@ -10,4 +12,5 @@ Dmitry Brant, 2017
1012
void main() {
1113
gl_Position = u_MVP * a_Position;
1214
gl_PointSize = u_PointThickness;
15+
v_Color = a_Color;
1316
}

0 commit comments

Comments
 (0)