use of org.joml.Vector3f in project lwjgl3-demos by LWJGL.
the class DemoSsboTrianglesStacklessKdTree method createSceneSSBO.
/**
* Build the kd-tree of the scene and create two SSBOs:
* <ul>
* <li>one for the nodes of the kd-tree
* <li>and another one to hold all the triangles stored in the leaf nodes of the kd-tree
* </ul>
*/
void createSceneSSBO() {
/* Build Kd-tree */
KDTree kdtree = new KDTree();
List<Triangle> triangles = new ArrayList<Triangle>();
int trianglesCount = mesh.positions.remaining() / 3 / 3;
sceneBounds = new Box();
Vector3f min = new Vector3f(Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE);
Vector3f max = new Vector3f(-Float.MAX_VALUE, -Float.MAX_VALUE, -Float.MAX_VALUE);
sceneBounds.min = min;
sceneBounds.max = max;
for (int i = 0; i < trianglesCount; i++) {
Triangle t = new Triangle();
t.v0 = new Vector3f(mesh.positions.get(i * 3 * 3 + 0), mesh.positions.get(i * 3 * 3 + 1), mesh.positions.get(i * 3 * 3 + 2));
t.v1 = new Vector3f(mesh.positions.get(i * 3 * 3 + 3), mesh.positions.get(i * 3 * 3 + 4), mesh.positions.get(i * 3 * 3 + 5));
t.v2 = new Vector3f(mesh.positions.get(i * 3 * 3 + 6), mesh.positions.get(i * 3 * 3 + 7), mesh.positions.get(i * 3 * 3 + 8));
triangles.add(t);
min.min(t.v0).min(t.v1).min(t.v2);
max.max(t.v0).max(t.v1).max(t.v2);
}
kdtree.buildTree(triangles, sceneBounds);
DynamicByteBuffer nodesBuffer = new DynamicByteBuffer();
DynamicByteBuffer trianglesBuffer = new DynamicByteBuffer();
kdTreeToBuffers(kdtree, nodesBuffer, trianglesBuffer);
nodesBuffer.flip();
trianglesBuffer.flip();
this.nodesSsbo = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, nodesSsbo);
glBufferData(GL_ARRAY_BUFFER, nodesBuffer.bb, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
this.trianglesSsbo = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, trianglesSsbo);
glBufferData(GL_ARRAY_BUFFER, trianglesBuffer.bb, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
use of org.joml.Vector3f in project lwjgl3-demos by LWJGL.
the class HybridDemoSsbo method createSceneSSBO.
/**
* Create a Shader Storage Buffer Object which will hold our boxes to be
* read by our Compute Shader.
*/
private void createSceneSSBO() {
this.ssbo = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, ssbo);
ByteBuffer ssboData = BufferUtils.createByteBuffer(4 * (4 + 4) * boxes.length / 2);
FloatBuffer fv = ssboData.asFloatBuffer();
for (int i = 0; i < boxes.length; i += 2) {
Vector3f min = boxes[i];
Vector3f max = boxes[i + 1];
/*
* NOTE: We need to write vec4 here, because SSBOs have specific
* alignment requirements for struct members (vec3 is always treated
* as vec4 in memory!)
*
* See:
* "https://www.safaribooksonline.com/library/view/opengl-programming-guide/9780132748445/app09lev1sec3.html"
*/
fv.put(min.x).put(min.y).put(min.z).put(0.0f);
fv.put(max.x).put(max.y).put(max.z).put(0.0f);
}
glBufferData(GL_ARRAY_BUFFER, ssboData, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
use of org.joml.Vector3f in project lwjgl3-demos by LWJGL.
the class HybridDemoSsboInstancing method createSceneVao.
/**
* Creates a VAO for the scene.
*/
private void createSceneVao() {
int vao = glGenVertexArrays();
/* Create vertex data */
int vbo = glGenBuffers();
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
ByteBuffer bb = BufferUtils.createByteBuffer(4 * (3 + 3) * 6 * 6);
FloatBuffer fv = bb.asFloatBuffer();
DemoUtils.triangulateUnitBox(fv);
glBufferData(GL_ARRAY_BUFFER, bb, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 4 * (3 + 3), 0L);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, false, 4 * (3 + 3), 4 * 3);
glBindBuffer(GL_ARRAY_BUFFER, 0);
/* Create per instance data (position and size of box) */
int ivbo = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, ivbo);
bb = BufferUtils.createByteBuffer(4 * (3 + 3) * boxes.length);
fv = bb.asFloatBuffer();
for (int i = 0; i < boxes.length; i += 2) {
Vector3f min = boxes[i];
Vector3f max = boxes[i + 1];
fv.put((max.x + min.x) / 2.0f).put((max.y + min.y) / 2.0f).put((max.z + min.z) / 2.0f);
fv.put((max.x - min.x) / 2.0f).put((max.y - min.y) / 2.0f).put((max.z - min.z) / 2.0f);
}
glBufferData(GL_ARRAY_BUFFER, bb, GL_STATIC_DRAW);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 3, GL_FLOAT, false, 4 * (3 + 3), 0L);
glVertexAttribDivisor(2, 1);
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 3, GL_FLOAT, false, 4 * (3 + 3), 4 * 3);
glVertexAttribDivisor(3, 1);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
this.vaoScene = vao;
}
use of org.joml.Vector3f in project lwjgl3-demos by LWJGL.
the class HybridDemoSsboInstancing45 method createSceneVao.
/**
* Creates a VAO for the scene.
*/
private void createSceneVao() {
int vao = glCreateVertexArrays();
/* Create vertex data */
int vbo = glCreateBuffers();
ByteBuffer bb = BufferUtils.createByteBuffer(4 * (3 + 3) * 6 * 6);
FloatBuffer fv = bb.asFloatBuffer();
DemoUtils.triangulateUnitBox(fv);
glNamedBufferData(vbo, bb, GL_STATIC_DRAW);
glEnableVertexArrayAttrib(vao, 0);
glVertexArrayAttribFormat(vao, 0, 3, GL_FLOAT, false, 0);
glVertexArrayVertexBuffer(vao, 0, vbo, 0L, 4 * (3 + 3));
glVertexArrayAttribBinding(vao, 0, 0);
glEnableVertexArrayAttrib(vao, 1);
glVertexArrayAttribFormat(vao, 1, 3, GL_FLOAT, false, 0);
glVertexArrayVertexBuffer(vao, 1, vbo, 4 * 3, 4 * (3 + 3));
glVertexArrayAttribBinding(vao, 1, 1);
/* Create per instance data (position and size of box) */
int ivbo = glCreateBuffers();
bb = BufferUtils.createByteBuffer(4 * (3 + 3) * boxes.length);
fv = bb.asFloatBuffer();
for (int i = 0; i < boxes.length; i += 2) {
Vector3f min = boxes[i];
Vector3f max = boxes[i + 1];
fv.put((max.x + min.x) / 2.0f).put((max.y + min.y) / 2.0f).put((max.z + min.z) / 2.0f);
fv.put((max.x - min.x) / 2.0f).put((max.y - min.y) / 2.0f).put((max.z - min.z) / 2.0f);
}
glNamedBufferData(ivbo, bb, GL_STATIC_DRAW);
glEnableVertexArrayAttrib(vao, 2);
glVertexArrayAttribFormat(vao, 2, 3, GL_FLOAT, false, 0);
glVertexArrayVertexBuffer(vao, 2, ivbo, 0L, 4 * (3 + 3));
glVertexArrayAttribBinding(vao, 2, 2);
glVertexArrayBindingDivisor(vao, 2, 1);
glEnableVertexArrayAttrib(vao, 3);
glVertexArrayAttribFormat(vao, 3, 3, GL_FLOAT, false, 0);
glVertexArrayVertexBuffer(vao, 3, ivbo, 4 * 3, 4 * (3 + 3));
glVertexArrayAttribBinding(vao, 3, 3);
glVertexArrayBindingDivisor(vao, 3, 1);
this.vaoScene = vao;
}
use of org.joml.Vector3f in project lwjgl3-demos by LWJGL.
the class KDTree method findSplitPlane.
// find optimal split
private float findSplitPlane(Node node) {
if (node == null) {
return Float.POSITIVE_INFINITY;
}
Split strategy = mSplitStrategy;
// use arithmetic average
if (strategy.equals(Split.MEAN)) {
float avg = 0.0f;
for (int i = 0; i < node.triangles.size(); i++) {
Box bounds = node.triangles.get(i).getBounds();
avg += (Vector3f_get(bounds.min, node.splitAxis.dim) + Vector3f_get(bounds.max, node.splitAxis.dim)) * 0.5f;
}
avg /= node.triangles.size();
return avg;
}
// use median
if (strategy.equals(Split.MEDIAN)) {
List<Float> vecIntervalMeans = new ArrayList<Float>(node.triangles.size());
for (int i = 0; i < node.triangles.size(); i++) {
Box bounds = node.triangles.get(i).getBounds();
vecIntervalMeans.add(Float.valueOf(0.5f * (Vector3f_get(bounds.min, node.splitAxis.dim) + Vector3f_get(bounds.max, node.splitAxis.dim))));
}
Collections.sort(vecIntervalMeans);
return vecIntervalMeans.get(vecIntervalMeans.size() / 2).floatValue();
}
// use surface area heuristic
if (strategy.equals(Split.SAH)) {
Box bb = node.boundingBox;
int nPrims = node.triangles.size();
// do a complete scan
if (nPrims > mSahThreshold) {
// sampleing
Vector3f costvector = new Vector3f(bb.max).sub(bb.min);
int ax = Vector3f_maxDimension(costvector);
float box_width = Vector3f_get(bb.max, ax) - Vector3f_get(bb.min, ax);
if (box_width <= EPSILON) {
node.splitAxis = Axis.NO_AXIS;
return Float.POSITIVE_INFINITY;
}
float inv_box_width = 1.0f / box_width;
if (box_width < 0.0f) {
throw new IllegalStateException("!!! KDTree.findSplitPlane: invalid box width < 0");
}
// triangle counts for histogram
int[] p = new int[mSahRes];
int[] h = new int[mSahRes];
int[] p_rtl = new int[mSahRes];
float triangleLeftEdge;
// build histogram
for (int i = 0; i < nPrims; i++) {
Box bounds = node.triangles.get(i).getBounds();
triangleLeftEdge = Math.min(Vector3f_get(bb.max, ax), Math.max(Vector3f_get(bb.min, ax), (Vector3f_get(bounds.min, ax) + Vector3f_get(bounds.max, ax)) * 0.5f)) - Vector3f_get(bb.min, ax);
if (!bb.intersectsWithBox(bounds)) {
throw new IllegalStateException("!!! KDTree.findSplitPlane: no intersection of boxes!");
}
if (triangleLeftEdge < 0.0 || inv_box_width * triangleLeftEdge > 1.0f + EPSILON) {
throw new IllegalStateException("!!! KDTree.findSplitPlane: triangleLeftEdge invalid : " + triangleLeftEdge + ", " + (inv_box_width * triangleLeftEdge));
}
float hf = inv_box_width * (triangleLeftEdge - EPSILON) * (mSahRes - 1.0f);
h[(int) hf] += 1;
}
// copy p for right-to-left lookup
for (int i = 0; i < mSahRes - 1; i++) {
p[i] = h[i + 1];
}
for (int i = 0; i < mSahRes - 1; i++) {
p_rtl[i] = p[i + 1];
}
p_rtl[mSahRes - 1] = 0;
// convert p and p_rtl into cumulative quantities
for (int i = 1; i < mSahRes; i++) {
p[i] += p[i - 1];
}
for (int i = mSahRes - 2; i >= 0; i--) {
p_rtl[i] += p_rtl[i + 1];
}
// splitting costs
float[] costs = new float[mSahRes - 1];
// determine costs
for (int i = 0; i < mSahRes - 1; i++) {
costs[i] = mSahTrvCosts + mSahIntCosts * ((i + 1) * p[i] + (mSahRes - i - 1) * p_rtl[i]) / mSahRes;
}
int minid = 0;
float minval = costs[0];
// find minimum
for (int i = 0; i < mSahRes - 1; i++) {
if (minval > costs[i]) {
minval = costs[i];
minid = i;
}
}
float splitPosition = ((minid + 1.0f) / mSahRes) * box_width + Vector3f_get(bb.min, ax);
node.splitAxis = Axis.values()[ax];
return splitPosition;
}
// complete scan
Vector3f costvector = new Vector3f(bb.max).sub(bb.min);
int ax = Vector3f_maxDimension(costvector);
float box_width = Vector3f_get(costvector, ax);
// only split if it makes sense
if (box_width <= EPSILON) {
node.splitAxis = Axis.NO_AXIS;
return Float.POSITIVE_INFINITY;
}
float inv_box_width = 1.0f / box_width;
if (box_width <= EPSILON) {
throw new IllegalStateException("!!! KDTree.findSplitPlane: box to small");
}
List<IntervalBoundary> intervals = new ArrayList<IntervalBoundary>();
// find splitpositions
for (int i = 0; i < nPrims; i++) {
Box b = node.triangles.get(i).getBounds();
if (!bb.intersectsWithBox(b)) {
throw new IllegalStateException("!!! KDTree.findSplitPlane: no intersection of boxes");
}
intervals.add(new IntervalBoundary(BoundaryType.LOWER_BOUND, Vector3f_get(b.min, ax)));
intervals.add(new IntervalBoundary(BoundaryType.UPPER_BOUND, Vector3f_get(b.max, ax)));
}
Collections.sort(intervals, new Comparator<IntervalBoundary>() {
@Override
public int compare(IntervalBoundary sib1, IntervalBoundary sib2) {
return sib1.compareTo(sib2);
}
});
int done_intervals = 0;
int open_intervals = 0;
float alpha;
// find minimum cost
int minid = 0;
float mincost = Float.MAX_VALUE;
for (int i = 0; i < intervals.size(); i++) {
if (intervals.get(i).type.equals(BoundaryType.UPPER_BOUND)) {
open_intervals--;
done_intervals++;
}
alpha = (intervals.get(i).pos - Vector3f_get(bb.min, ax)) * inv_box_width;
float cost = mSahTrvCosts + mSahIntCosts * ((done_intervals + open_intervals) * alpha + (nPrims - done_intervals) * (1.0f - alpha));
if (cost < mincost) {
minid = i;
mincost = cost;
}
if (intervals.get(i).type.equals(BoundaryType.LOWER_BOUND)) {
open_intervals++;
}
}
float splitPlane = intervals.get(minid).pos;
// no cuts at the boundaries
if (splitPlane == Vector3f_get(bb.min, ax) || splitPlane == Vector3f_get(bb.max, ax)) {
node.splitAxis = Axis.NO_AXIS;
return Float.POSITIVE_INFINITY;
}
node.splitAxis = Axis.values()[ax];
return intervals.get(minid).pos;
}
throw new IllegalStateException("!!! KDTree.findSplitPlane: invalid value");
}
Aggregations