Create custom volume from slices

Started by gerferra, August 23, 2010, 03:19:37 PM

Previous topic - Next topic

gerferra

Ok.

Thank you very much.

Regards,
Germán.

EgonOlsen

#16
Maybe this helps to get you started...a simple "slices viewer" of random slices:


import java.util.ArrayList;
import java.util.List;

import org.lwjgl.input.Mouse;

import com.threed.jpct.Camera;
import com.threed.jpct.FrameBuffer;
import com.threed.jpct.IRenderer;
import com.threed.jpct.Matrix;
import com.threed.jpct.Object3D;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.World;
import com.threed.jpct.util.Light;

public class HullCreator {

private FrameBuffer buffer = null;

private World world = null;

private List<List<SimpleVector>> slices = new ArrayList<List<SimpleVector>>();

private List<Object3D> sliceObjs = new ArrayList<Object3D>();

private float distance = 100f;

public static void main(String[] args) {
HullCreator hc = new HullCreator();
hc.doIt();
}

private void doIt() {
init();
createSlices(5);
createSliceObjects();
render();
}

private void render() {
world.buildAllObjects();
Camera cam = world.getCamera();

while (!org.lwjgl.opengl.Display.isCloseRequested()) {
buffer.clear();
world.renderScene(buffer);
world.draw(buffer);
buffer.update();
buffer.displayGLOnly();

// Camera movement
int x = Mouse.getDX();
int y = Mouse.getDY();
int w = Mouse.getDWheel();

if (Mouse.isButtonDown(0)) {
SimpleVector line = new SimpleVector(x, 0, y);
Matrix m = line.normalize().getRotationMatrix();
m.rotateAxis(m.getXAxis(), (float) -Math.PI / 2f);
cam.moveCamera(Camera.CAMERA_MOVEIN, distance);
cam.rotateAxis(m.invert3x3().getXAxis(), line.length() / 200f);
cam.moveCamera(Camera.CAMERA_MOVEOUT, distance);
}
if (w != 0) {
float d = w / 200f;
distance -= d;
cam.moveCamera(Camera.CAMERA_MOVEIN, d);
}

try {
Thread.sleep(10);
} catch (InterruptedException e) {
}
}

}

private void init() {
buffer = new FrameBuffer(800, 600, FrameBuffer.SAMPLINGMODE_HARDWARE_ONLY);
buffer.disableRenderer(IRenderer.RENDERER_SOFTWARE);
buffer.enableRenderer(IRenderer.RENDERER_OPENGL);

world = new World();
world.getCamera().moveCamera(Camera.CAMERA_MOVEOUT, 100);
world.getCamera().moveCamera(Camera.CAMERA_MOVEUP, 25);
world.setAmbientLight(100, 100, 100);

Light light = new Light(world);
light.setIntensity(200, 200, 255);
}

/**
* Create objects that visualize the slices
*
* @param world
*/
private void createSliceObjects() {
for (List<SimpleVector> data : slices) {

Object3D slice = new Object3D(0);

for (int i = 0; i < data.size(); i++) {

Object3D part = new Object3D(6);

SimpleVector p0 = data.get(i);
SimpleVector p1 = data.get((i + 1) % data.size());
SimpleVector a = p1.calcSub(p0);

Matrix rot = a.getRotationMatrix();
SimpleVector xd = rot.getXAxis();
SimpleVector yd = rot.getYAxis();

xd.scalarMul(0.5f);
yd.scalarMul(0.5f);

SimpleVector p0u = new SimpleVector(p0);
p0u.add(yd);
yd.scalarMul(-1);
SimpleVector p0r = new SimpleVector(p0);
p0r.add(yd);
p0r.add(xd);
xd.scalarMul(-1);
SimpleVector p0l = new SimpleVector(p0);
p0l.add(yd);
p0l.add(xd);

yd.scalarMul(-1);
xd.scalarMul(-1);
SimpleVector p1u = new SimpleVector(p1);
p1u.add(yd);
yd.scalarMul(-1);
SimpleVector p1r = new SimpleVector(p1);
p1r.add(yd);
p1r.add(xd);
xd.scalarMul(-1);
SimpleVector p1l = new SimpleVector(p1);
p1l.add(yd);
p1l.add(xd);

part.addTriangle(p0u, p1u, p0l);
part.addTriangle(p0l, p1u, p1l);

part.addTriangle(p0u, p0r, p1u);
part.addTriangle(p1u, p0r, p1r);

part.addTriangle(p0r, p0l, p1l);
part.addTriangle(p1l, p1r, p0r);

part.scale(1.05f);
part.rotateMesh();
part.clearRotation();

slice = Object3D.mergeObjects(slice, part);
}

slice.setCulling(false);
world.addObject(slice);
sliceObjs.add(slice);
}

}

/**
* Creates random slices
*
* @param cnt
*/
private void createSlices(int cnt) {
float yStart = 0;

for (int i = 0; i < cnt; i++) {
List<SimpleVector> data = new ArrayList<SimpleVector>();
int pointCnt = (int) (Math.random() * 10f + 5f);
float delta = (float) (2d * Math.PI) / (pointCnt+1);
SimpleVector midPoint = new SimpleVector(0, yStart, 0);
SimpleVector orbit = new SimpleVector(0, 0, 10);
float rot = 0;
for (int p = 0; p < pointCnt; p++) {
float r = (float) Math.random() / 5f;
if (rot + r < Math.PI * 2f) {
orbit.rotateY(r);
rot += r;
}
if (rot + delta < Math.PI * 2f) {
orbit.rotateY(delta);
rot += delta;
}

SimpleVector to = new SimpleVector(orbit);
float s = to.length();

s = s + (float) Math.random() * 10f;
to = to.normalize();
to.scalarMul(s);

SimpleVector res = new SimpleVector(midPoint);
res.add(to);

data.add(res);
}
slices.add(data);
yStart -= 10;
}
}

}



Edit: Corrected creation of the random values a little bit...

gerferra

Excelent! This is more than I expected, you saved me also having to ask about how to interact with the mouse :)

Thank you.

Regards,
Germán

EgonOlsen

And the same thing with hull creation...works reasonable for the test data. It implements the algorithm mentioned above. Apart from the hull (can be made invisible by pressing the right mouse button), i've changed object creation for the slices outlines, because i've used some scaling before to fill the gaps between the vertices, which isn't a good idea. I'm using slightly longer vertices now.

BTW: This isn't the usual kind of support that i offer, but the topic somehow got me interested...i wanted to see if my naive idea would actual work... ;D


import java.util.ArrayList;
import java.util.List;

import org.lwjgl.input.Mouse;

import com.threed.jpct.Camera;
import com.threed.jpct.FrameBuffer;
import com.threed.jpct.IRenderer;
import com.threed.jpct.Matrix;
import com.threed.jpct.Object3D;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.World;
import com.threed.jpct.util.Light;

public class HullCreator {

private FrameBuffer buffer = null;

private World world = null;

private List<List<SimpleVector>> slices = new ArrayList<List<SimpleVector>>();

private List<List<SimpleVector>> enhancedSlices = new ArrayList<List<SimpleVector>>();

private List<Object3D> sliceObjs = new ArrayList<Object3D>();

private float distance = 100f;

private Object3D hull = null;

public static void main(String[] args) {
HullCreator hc = new HullCreator();
hc.doIt();
}

private void doIt() {
init();
createSlices(5);
enhanceSlices();
createSliceObjects();
createHull();
render();
}

/**
* Creates a hull based on the enhanced slices
*/
private void createHull() {
hull = new Object3D(0);

for (int i = 0; i < enhancedSlices.size() - 1; i++) {

Object3D part = new Object3D(enhancedSlices.get(i).size() * 2);

List<SimpleVector> points = enhancedSlices.get(i);
List<SimpleVector> nextPoints = enhancedSlices.get(i + 1);
SimpleVector p0 = points.get(0);
float minDist = -1;
int npStart = 0;
int cnt = 0;
for (SimpleVector pn : nextPoints) {
float dist = pn.distance(p0);
if (dist < minDist) {
npStart = cnt;
minDist = dist;
}
cnt++;
}
for (int p = 0; p < points.size(); p++) {
p0 = points.get(p);
SimpleVector p1 = points.get((p + 1) % points.size());
SimpleVector p2 = nextPoints.get((p + npStart) % points.size());
SimpleVector p3 = nextPoints.get((p + 1 + npStart) % points.size());

part.addTriangle(p0, p3, p2);
part.addTriangle(p0, p1, p3);
}

hull = Object3D.mergeObjects(hull, part);
}
hull.setCulling(false);
world.addObject(hull);
}

private void render() {
world.buildAllObjects();
Camera cam = world.getCamera();

while (!org.lwjgl.opengl.Display.isCloseRequested()) {
if (Mouse.isButtonDown(1)) {
hull.setVisibility(false);
} else {
hull.setVisibility(true);
}

buffer.clear();
world.renderScene(buffer);
world.draw(buffer);
buffer.update();
buffer.displayGLOnly();

// Camera movement
int x = Mouse.getDX();
int y = Mouse.getDY();
int w = Mouse.getDWheel();

if (Mouse.isButtonDown(0)) {
SimpleVector line = new SimpleVector(x, 0, y);
Matrix m = line.normalize().getRotationMatrix();
m.rotateAxis(m.getXAxis(), (float) -Math.PI / 2f);
cam.moveCamera(Camera.CAMERA_MOVEIN, distance);
cam.rotateAxis(m.invert3x3().getXAxis(), line.length() / 200f);
cam.moveCamera(Camera.CAMERA_MOVEOUT, distance);
}
if (w != 0) {
float d = w / 200f;
distance -= d;
cam.moveCamera(Camera.CAMERA_MOVEIN, d);
}

try {
Thread.sleep(10);
} catch (InterruptedException e) {
}
}
}

private void init() {
buffer = new FrameBuffer(800, 600, FrameBuffer.SAMPLINGMODE_HARDWARE_ONLY);
buffer.disableRenderer(IRenderer.RENDERER_SOFTWARE);
buffer.enableRenderer(IRenderer.RENDERER_OPENGL);

world = new World();
world.getCamera().moveCamera(Camera.CAMERA_MOVEOUT, 100);
world.getCamera().moveCamera(Camera.CAMERA_MOVEUP, 25);
world.setAmbientLight(100, 100, 100);

Light light = new Light(world);
light.setIntensity(0, 0, 255);
light.setPosition(world.getCamera().getPosition());

light = new Light(world);
light.setIntensity(255, 0, 0);
light.setPosition(new SimpleVector(0,-40,100));
}

/**
* Creates additional points. Rough algorithm...just a brain fart of
* mine...maybe it's faulty, but it seems to work reasonable well
* for the generated test data.
*/
private void enhanceSlices() {
boolean added = false;
do {
added = false;
boolean firstRun = enhancedSlices.size() == 0;
List<List<SimpleVector>> ds = slices;
if (!firstRun) {
ds = enhancedSlices;
}
int maxPoints = 0;
List<Float> lengths = new ArrayList<Float>();
for (List<SimpleVector> data : ds) {
if (data.size() > maxPoints) {
maxPoints = data.size();
}
float len = 0;
for (int i = 0; i < data.size(); i++) {
SimpleVector p0 = data.get(i);
SimpleVector p1 = data.get((i + 1) % data.size());
SimpleVector a = p1.calcSub(p0);
len += a.length();
}
lengths.add(Float.valueOf(len));
}

int cnt = 0;

for (List<SimpleVector> data : slices) {
List<SimpleVector> newData = null;
if (firstRun) {
newData = new ArrayList<SimpleVector>(data);
} else {
newData = enhancedSlices.get(cnt);
}

if (newData.size() < maxPoints) {
int toAdd = maxPoints - data.size();
int div = toAdd + 1;
float delta = lengths.get(cnt) / div;
float len = 0;

for (int i = 0; i < newData.size(); i++) {
SimpleVector p0 = newData.get(i);
SimpleVector p1 = newData.get((i + 1) % newData.size());
SimpleVector a = p1.calcSub(p0);
float alen = a.length();
len += alen;
if (len > delta) {
len = alen / 2;
a.scalarMul(0.5f);
SimpleVector c = new SimpleVector(p0);
c.add(a);
newData.add((i + 1) % newData.size(), c);
added = true;
i++;
}
if (newData.size() == maxPoints) {
break;
}
}

}
if (firstRun) {
enhancedSlices.add(newData);
}
cnt++;
}
} while (added);
}

/**
* Create objects that visualize the slices
*
* @param world
*/
private void createSliceObjects() {
for (List<SimpleVector> data : slices) {

Object3D slice = new Object3D(0);

for (int i = 0; i < data.size(); i++) {

Object3D part = new Object3D(6);

SimpleVector p0 = data.get(i);
SimpleVector p1 = data.get((i + 1) % data.size());
SimpleVector a = p1.calcSub(p0);

Matrix rot = a.getRotationMatrix();
SimpleVector xd = rot.getXAxis();
SimpleVector yd = rot.getYAxis();
SimpleVector zd = rot.getZAxis();
zd=zd.normalize();
zd.scalarMul(0.2f);

xd.scalarMul(0.5f);
yd.scalarMul(0.5f);

SimpleVector p0u = new SimpleVector(p0);
p0u.add(yd);
yd.scalarMul(-1);
SimpleVector p0r = new SimpleVector(p0);
p0r.add(yd);
p0r.add(xd);
xd.scalarMul(-1);
SimpleVector p0l = new SimpleVector(p0);
p0l.add(yd);
p0l.add(xd);

yd.scalarMul(-1);
xd.scalarMul(-1);
SimpleVector p1u = new SimpleVector(p1);
p1u.add(yd);
yd.scalarMul(-1);
SimpleVector p1r = new SimpleVector(p1);
p1r.add(yd);
p1r.add(xd);
xd.scalarMul(-1);
SimpleVector p1l = new SimpleVector(p1);
p1l.add(yd);
p1l.add(xd);

p1u.add(zd);
p1r.add(zd);
p1l.add(zd);

part.addTriangle(p0u, p1u, p0l);
part.addTriangle(p0l, p1u, p1l);

part.addTriangle(p0u, p0r, p1u);
part.addTriangle(p1u, p0r, p1r);

part.addTriangle(p0r, p0l, p1l);
part.addTriangle(p1l, p1r, p0r);

part.rotateMesh();
part.clearRotation();

slice = Object3D.mergeObjects(slice, part);
}

slice.setCulling(false);
world.addObject(slice);
sliceObjs.add(slice);
}

}

/**
* Creates random slices
*
* @param cnt
*/
private void createSlices(int cnt) {
float yStart = 0;

for (int i = 0; i < cnt; i++) {
List<SimpleVector> data = new ArrayList<SimpleVector>();
int pointCnt = (int) (Math.random() * 10f + 5f);
float delta = (float) (2d * Math.PI) / (pointCnt + 1);
SimpleVector midPoint = new SimpleVector(0, yStart, 0);
SimpleVector orbit = new SimpleVector(0, 0, 10);
float rot = 0;
for (int p = 0; p < pointCnt; p++) {
float r = (float) Math.random() / 5f;
if (rot + r < Math.PI * 2f) {
orbit.rotateY(r);
rot += r;
}
if (rot + delta < Math.PI * 2f) {
orbit.rotateY(delta);
rot += delta;
}

SimpleVector to = new SimpleVector(orbit);
float s = to.length();

s = s + (float) Math.random() * 10f;
to = to.normalize();
to.scalarMul(s);

SimpleVector res = new SimpleVector(midPoint);
res.add(to);

data.add(res);
}
slices.add(data);
yStart -= 10;
}
}

}


EgonOlsen

Disclaimer: The whole thing is pretty hacky. Especially the creation of additional points is questionable. It uses a kind of multi-pass-threshold-subdivision-thing of algorithm that most likely won't make it into any book about graphics programming... ;D

gerferra

QuoteBTW: This isn't the usual kind of support that i offer, but the topic somehow got me interested...i wanted to see if my naive idea would actual work...  ;D
Maybe the mix between a "strange english" and bad terminology contributed :)

Well, I think I have a very good start for what I want to do. Thanks a lot!