I've been looking for hours now to find a good way to draw a textured sphere in JOGL. All I need is a point in the right direction or some code that works for someone. So far all I have been able to find is helloTexture (while it works, it is obviously not a sphere), would there be a way to convert this into a sphere or should i try my luck somewhere else?
I wrote this for you, it's untested since I modified it to work with GL_TRIANGLES, try and let me know
radius is the sphere radius, rings are the horizontal slices, sectors the vertical ones
private void createGeometry(float radius, short rings, short sectors) {
float R = 1f / (float)(rings - 1);
float S = 1f / (float)(sectors - 1);
short r, s;
float x, y, z;
points = new float[rings * sectors * 3];
normals = new float[rings * sectors * 3];
texcoords = new float[rings * sectors * 2];
int t = 0, v = 0, n = 0;
for(r = 0; r < rings; r++) {
for(s = 0; s < sectors; s++) {
x = (float) (Math.cos(2 * Math.PI * s * S) * Math.sin(Math.PI * r * R ));
y = (float) Math.sin(-Math.PI / 2 + Math.PI * r * R );
z = (float) (Math.sin(2 * Math.PI * s * S) * Math.sin(Math.PI * r * R ));
texcoords[t++] = s * S;
texcoords[t++] = r * R;
points[v++] = x * radius;
points[v++] = y * radius;
points[v++] = z * radius;
normals[n++] = x;
normals[n++] = y;
normals[n++] = z;
}
}
int counter = 0;
indices = new short[rings * sectors * 6];
for(r = 0; r < rings - 1; r++){
for(s = 0; s < sectors-1; s++) {
indices[counter++] = (short) (r * sectors + s);
indices[counter++] = (short) (r * sectors + (s + 1));
indices[counter++] = (short) ((r + 1) * sectors + (s + 1));
indices[counter++] = (short) ((r + 1) * sectors + (s + 1));
indices[counter++] = (short) (r * sectors + (s + 1));
indices[counter++] = (short) ((r + 1) * sectors + s);
}
}
}
Related
I am making a software that has a screen filtering process. The code can already shift the colors and apply it to the frame the only problem is that It takes around 40-50 seconds for the filtered window to render. Is there any way I can make it faster? I would also like to ask which part of the code makes the process longer and time consuming. I will really appreciate the help. Thanks!
Here is my code.
public RedGreenFilter(int k1, int k2, int k3) {
this.k1 = k1;
this.k2 = k2;
this.k3 = k3;
}
#Override
public BufferedImage filter(final BufferedImage src, BufferedImage dst) {
if (dst == null) {
dst = this.createCompatibleDestImage(src, null);
}
// make sure the two images have the same size, color space, etc.
// MISSING !!! ???
DataBufferInt inBuffer = (DataBufferInt) src.getRaster().getDataBuffer();
DataBufferInt outBuffer = (DataBufferInt) dst.getRaster().getDataBuffer();
int[] inData = inBuffer.getData();
int[] outData = outBuffer.getData();
int simR = 0, simG = 0, simB = 0, mild = 10, moderate = 20, strong = 40;
float cIndex = MyDeficiency.cIndex;
float angle = MyDeficiency.angle;
float x = 0, y = 0, z = 0;
int prevIn = 0;
int prevOut = 0;
final int length = inData.length;
int corrG;
int corrR;
int corrB;
int SizeOfScreen = src.getHeight() * src.getWidth();
final int[] redArray = new int[SizeOfScreen];
final int[] blueArray = new int[SizeOfScreen];
final int[] greenArray = new int[SizeOfScreen];
for (int i = 0; i < SizeOfScreen; i++) {
final int in = inData[i];
if (in == prevIn) {
outData[i] = prevOut;
} else {
final int r = (0xff0000 & in) >> 16;
final int g = (0xff00 & in) >> 8;
final int b = 0xff & in;
// get linear rgb values in the range 0..2^15-1
final int r_lin = rgb2lin_red_LUT[r];
final int g_lin = rgb2lin_red_LUT[g];
final int b_lin = rgb2lin_red_LUT[b];
//http://publication.gunadarma.ac.id/bitstream/123456789/12232/1/Slide_Mahendra_54411250.pdf
float L = (17.8824f * r + 43.5161f * g + 4.11935f * b);
float M = (3.4565f * r + 27.1554f * g + 3.86714f * b);
float S = (0.02996f * r + 0.18431f * g + 1.46709f * b);
float dL = ( 0 * L + 2.02344f * M - 2.52581f * S);
float dM = ( 0 * L + 1 * M + 0 * S);
float dS = ( 0 * L + 0 * M + 1 * S);
float pL = ( 1 * L + 0 * M + 0 * S);
float pM = ( 0.494207f * L + 0 * M + 1.24827f * S);
float pS = ( 0 * L + 0 * M + 1 * S);
// simulated red and green are identical
// scale the matrix values to 0..2^15 for integer computations
// of the simulated protan values.
// divide after the computation by 2^15 to rescale.
// also divide by 2^15 asnd multiply by 2^8 to scale the linear rgb to 0..255
// total division is by 2^15 * 2^15 / 2^8 = 2^22
// shift the bits by 22 places instead of dividing
int r_blind = (int) (k1 * r_lin + k2 * g_lin) >> 22;
int b_blind = (int) (k3 * r_lin - k3 * g_lin + 32768 * b_lin) >> 22;
if (r_blind < 0) {
r_blind = 0;
} else if (r_blind > 255) {
r_blind = 255;
}
if (b_blind < 0) {
b_blind = 0;
} else if (b_blind > 255) {
b_blind = 255;
}
// convert reduced linear rgb to gamma corrected rgb
int red = lin2rgb_LUT[r_blind];
red = red >= 0 ? red : 256 + red; // from unsigned to signed
int blue = lin2rgb_LUT[b_blind];
blue = blue >= 0 ? blue : 256 + blue; // from unsigned to signed
if(k1 == 9591 && k2 == 23173){
x = dL;
y = dM;
z = dS;
}
if(k1 == 3683 && k2 == 29084){
x = pL;
y = pM;
z = pS;
}
//SEVERITY
//PROTAN
//normal to mild
if (angle > 0.70 && cIndex < 1.2){
simR = (int)(0.0809533970341018f * x -0.1305188419612954f * y + 0.11673398252989027f * z);
simG = (int)(-0.01025222049871863f * x + 0.054025275314902886f * y -0.11362003603724172f * z);
simB = (int)(-0.0003651971010795924f * x -0.004121801653701777f * y + 0.693511617368688f * z);
}
//mild to moderate
else if (angle > 0.70 && cIndex < 3 && cIndex > 1.20){
simR = (int)(0.0809533970341018f * x -0.1305188419612954f * y + 0.11673398252989027f * z) + mild;
simG = (int)(-0.01025222049871863f * x + 0.054025275314902886f * y -0.11362003603724172f * z);
simB = (int)(-0.0003651971010795924f * x -0.004121801653701777f * y + 0.693511617368688f * z);
}
//moderate to strong
else if (angle > 0.70 && cIndex < 4 && cIndex > 3){
simR = (int)(0.0809533970341018f * x -0.1305188419612954f * y + 0.11673398252989027f * z) + moderate;
simG = (int)(-0.01025222049871863f * x + 0.054025275314902886f * y -0.11362003603724172f * z);
simB = (int)(-0.0003651971010795924f * x -0.004121801653701777f * y + 0.693511617368688f * z);
}
//strong to super strong
else if (angle > 0.70 && cIndex > 4){
simR = (int)(0.0809533970341018f * x -0.1305188419612954f * y + 0.11673398252989027f * z) + strong;
simG = (int)(-0.01025222049871863f * x + 0.054025275314902886f * y -0.11362003603724172f * z);
simB = (int)(-0.0003651971010795924f * x -0.004121801653701777f * y + 0.693511617368688f * z);
}
//DEUTAN
//normal to mild
if (angle < 0.70 && angle > -65.00 && cIndex < 1.2){
simR = (int)(0.0809533970341018f * x -0.1305188419612954f * y + 0.11673398252989027f * z);
simG = (int)(-0.01025222049871863f * x + 0.054025275314902886f * y -0.11362003603724172f * z);
simB = (int)(-0.0003651971010795924f * x -0.004121801653701777f * y + 0.693511617368688f * z);
}
//mild to moderate
else if (angle < 0.70 && angle > -65.00 && cIndex < 3 && cIndex > 1.20){
simR = (int)(0.0809533970341018f * x -0.1305188419612954f * y + 0.11673398252989027f * z);
simG = (int)(-0.01025222049871863f * x + 0.054025275314902886f * y -0.11362003603724172f * z) + mild;
simB = (int)(-0.0003651971010795924f * x -0.004121801653701777f * y + 0.693511617368688f * z);
}
//moderate to strong
else if (angle < 0.70 && angle > -65 && cIndex < 4 && cIndex > 3){
simR = (int)(0.0809533970341018f * x -0.1305188419612954f * y + 0.11673398252989027f * z);
simG = (int)(-0.01025222049871863f * x + 0.054025275314902886f * y -0.11362003603724172f * z) + moderate;
simB = (int)(-0.0003651971010795924f * x -0.004121801653701777f * y + 0.693511617368688f * z) ;
}
//strong to super strong
else if (angle < 0.7 && angle > -65 && cIndex > 4){
simR = (int)(0.0809533970341018f * x -0.1305188419612954f * y + 0.11673398252989027f * z);
simG = (int)(-0.01025222049871863f * x + 0.054025275314902886f * y -0.11362003603724172f * z) + strong;
simB = (int)(-0.0003651971010795924f * x -0.004121801653701777f * y + 0.693511617368688f * z) ;
}
int errR = r - simR;
int errG = g - simG;
int errB = b - simB;
float errModR = (0 * errR + 0 * errG + 0 * errB);
float errModG = (0.7f * errR + 1 * errG + 0 * errB);
float errModB = (0.7f * errR + 0 * errG + 1 * errB);
corrR = (int) errModR + r;
corrG = (int) errModG + g;
corrB = (int) errModB + b;
/*
int corrR = 0;
int corrG = 0;
int corrB = 0;
*/
//MyDeficiency my = new MyDeficiency();
if(r == 255 && g == 255 && b == 255){
corrR = corrG = corrB = 255;
}
if(r == 0 && g == 0 && b == 0){
corrR = corrG = corrB = 0;
}
final int out = 0xff000000 | (corrR << 16) | (corrG << 8) | corrB ;
redArray[i] = (out >> 16) & 0xFF;
greenArray[i] = (out >> 8) & 0xFF;
blueArray[i] = (out >> 0) & 0xFF;
//System.out.println("r: " +" " + redArray[i]+ " "+ " g:" +" " +greenArray[i] +" " +"b:"+" "+ blueArray[i] + " " +"i:"+ " "+i);
//System.out.println("sR: " + (red << 16) + "sG: " +(red <<8)+ " sB: " + blue);
//outData[i] = out;
//prevIn = in;
//prevOut = out;
}
}
//System.out.println(SizeOfScreen);
Window w = new Window(null);
w.add(new JComponent() {
public void paintComponent(Graphics g) {
int alpha = 190; // 50% transparent
int pixelcounter = 0;
for(int i = 0; i < src.getHeight(); i++){
for(int j = 0; j < src.getWidth(); j++){
Color myColour = new Color(redArray[pixelcounter],greenArray[pixelcounter],blueArray[pixelcounter], alpha);
g.setColor(myColour);
g.fillRect(j,i,1,1);
pixelcounter++;
}
}
}
public Dimension getPreferredSize() {
return new Dimension(src.getWidth(), src.getHeight());
}
});
w.pack();
w.setLocationRelativeTo(null);
w.setAlwaysOnTop(true);
/**
* This sets the background of the window to be transparent.
*/
AWTUtilities.setWindowOpaque(w, false);
setTransparent(w);
w.setVisible(true);
//w.setVisible(false);
return dst;
}
}
Let's say I'm using the following code to create the vertices in a hexagon polygon:
hexagonPoints = new Array<Vector2>();
for (int a = 0; a < 6; a++)
{
float x = r * (float)Math.cos(a * 60 * Math.PI / 180f);
float y = r * (float)Math.sin(a * 60 * Math.PI / 180f);
hexagonPoints.add(new Vector2(x, y));
}
How can I add additional points along each side of the polygon, so that there are n additional points between each connecting set of vertices? All vertices must be equal distance (including the vertices that formed the initial shape). E.g. before:
. .
. .
After (where n = 1):
. . .
. .
. . .
edit: here's my current code based on Volker's suggestion:
float r = 3.0f;
int n = 1 + 2; // number of additional vertices between the main shape vertices
for (int a = 0; a < 6; a++)
{
float xe = r * (float)Math.cos(a * 60 * Math.PI / 180f);
float ye = r * (float)Math.sin(a * 60 * Math.PI / 180f);
if (a > 0)
{
for (int i = 1; i < n; ++i)
{
float xs = ((n - i) * hexagonPoints.get(a - 1).x + i * xe) / n;
float ys = ((n - i) * hexagonPoints.get(a - 1).y + i * ye) / n;
hexagonPoints.add(new Vector2(xs, ys));
}
}
hexagonPoints.add(new Vector2(xe, ye));
}
This plots the additional vertices, but they are not in the correct positions.
edit: seems this wasn't working because I wasn't taking into account the first vertex position.
Calculate the endpoints of each side as you are doing it already. Then introduce with an inner loop the additional splitting points.
for (int i=1; i<n: ++i)
{
float xs = ((n-i)*xb + i*xe)/n;
float ys = ((n-i)*yb + i*ye)/n;
hexagonPoints.add(new Vector(xs, ys));
}
hexagonPoints.add(new Vector(xe, ye));
where xb, yb is the beginning of a hexagon side and xe, ye the end.
Here's a working solution, based on Volker's suggestion:
int size = 6;
int npoints = 2;
int nsegs = npoints + 1;
float xb = r;
float yb = 0;
hexagonPoints.add(new Vector2(xb, yb));
for (int a = 1; a <= size; a++)
{
float xe = r * (float) Math.cos(a * 60 * Math.PI / 180f);
float ye = r * (float) Math.sin(a * 60 * Math.PI / 180f);
for (int i = 1; i < nsegs; ++i)
{
float xs = ((nsegs - i) * xb + i * xe) / nsegs;
float ys = ((nsegs - i) * yb + i * ye) / nsegs;
hexagonPoints.add(new Vector2(xs, ys));
}
if (a < size) hexagonPoints.add(new Vector2(xe, ye));
xb = xe;
yb = ye;
}
I'm trying to create a heightmap colored by face, instead of vertex. For example, this is what I currently have:
But this is what I want:
I read that I have to split each vertex into multiple vertices, then index each separately for the triangles. I also know that blender has a function like this for its models (split vertices, or something?), but I'm not sure what kind of algorithm I would follow for this. This would be the last resort, because multiplying the amount of vertices in the mesh for no reason other than color doesn't seem efficient.
I also discovered something called flatshading (using the flat qualifier on the pixel color in the shaders), but it seems to only draw squares instead of triangles. Is there a way to make it shade triangles?
For reference, this is my current heightmap generation code:
public class HeightMap extends GameModel {
private static final float START_X = -0.5f;
private static final float START_Z = -0.5f;
private static final float REFLECTANCE = .1f;
public HeightMap(float minY, float maxY, float persistence, int width, int height, float spikeness) {
super(createMesh(minY, maxY, persistence, width, height, spikeness), REFLECTANCE);
}
protected static Mesh createMesh(final float minY, final float maxY, final float persistence, final int width,
final int height, float spikeness) {
SimplexNoise noise = new SimplexNoise(128, persistence, 2);// Utils.getRandom().nextInt());
float xStep = Math.abs(START_X * 2) / (width - 1);
float zStep = Math.abs(START_Z * 2) / (height - 1);
List<Float> positions = new ArrayList<>();
List<Integer> indices = new ArrayList<>();
for (int z = 0; z < height; z++) {
for (int x = 0; x < width; x++) {
// scale from [-1, 1] to [minY, maxY]
float heightY = (float) ((noise.getNoise(x * xStep * spikeness, z * zStep * spikeness) + 1f) / 2
* (maxY - minY) + minY);
positions.add(START_X + x * xStep);
positions.add(heightY);
positions.add(START_Z + z * zStep);
// Create indices
if (x < width - 1 && z < height - 1) {
int leftTop = z * width + x;
int leftBottom = (z + 1) * width + x;
int rightBottom = (z + 1) * width + x + 1;
int rightTop = z * width + x + 1;
indices.add(leftTop);
indices.add(leftBottom);
indices.add(rightTop);
indices.add(rightTop);
indices.add(leftBottom);
indices.add(rightBottom);
}
}
}
float[] verticesArr = Utils.listToArray(positions);
Color c = new Color(147, 105, 59);
float[] colorArr = new float[positions.size()];
for (int i = 0; i < colorArr.length; i += 3) {
float brightness = (Utils.getRandom().nextFloat() - 0.5f) * 0.5f;
colorArr[i] = (float) c.getRed() / 255f + brightness;
colorArr[i + 1] = (float) c.getGreen() / 255f + brightness;
colorArr[i + 2] = (float) c.getBlue() / 255f + brightness;
}
int[] indicesArr = indices.stream().mapToInt((i) -> i).toArray();
float[] normalArr = calcNormals(verticesArr, width, height);
return new Mesh(verticesArr, colorArr, normalArr, indicesArr);
}
private static float[] calcNormals(float[] posArr, int width, int height) {
Vector3f v0 = new Vector3f();
Vector3f v1 = new Vector3f();
Vector3f v2 = new Vector3f();
Vector3f v3 = new Vector3f();
Vector3f v4 = new Vector3f();
Vector3f v12 = new Vector3f();
Vector3f v23 = new Vector3f();
Vector3f v34 = new Vector3f();
Vector3f v41 = new Vector3f();
List<Float> normals = new ArrayList<>();
Vector3f normal = new Vector3f();
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
if (row > 0 && row < height - 1 && col > 0 && col < width - 1) {
int i0 = row * width * 3 + col * 3;
v0.x = posArr[i0];
v0.y = posArr[i0 + 1];
v0.z = posArr[i0 + 2];
int i1 = row * width * 3 + (col - 1) * 3;
v1.x = posArr[i1];
v1.y = posArr[i1 + 1];
v1.z = posArr[i1 + 2];
v1 = v1.sub(v0);
int i2 = (row + 1) * width * 3 + col * 3;
v2.x = posArr[i2];
v2.y = posArr[i2 + 1];
v2.z = posArr[i2 + 2];
v2 = v2.sub(v0);
int i3 = (row) * width * 3 + (col + 1) * 3;
v3.x = posArr[i3];
v3.y = posArr[i3 + 1];
v3.z = posArr[i3 + 2];
v3 = v3.sub(v0);
int i4 = (row - 1) * width * 3 + col * 3;
v4.x = posArr[i4];
v4.y = posArr[i4 + 1];
v4.z = posArr[i4 + 2];
v4 = v4.sub(v0);
v1.cross(v2, v12);
v12.normalize();
v2.cross(v3, v23);
v23.normalize();
v3.cross(v4, v34);
v34.normalize();
v4.cross(v1, v41);
v41.normalize();
normal = v12.add(v23).add(v34).add(v41);
normal.normalize();
} else {
normal.x = 0;
normal.y = 1;
normal.z = 0;
}
normal.normalize();
normals.add(normal.x);
normals.add(normal.y);
normals.add(normal.z);
}
}
return Utils.listToArray(normals);
}
}
Edit
I've tried doing a couple things. I tried rearranging the indices with flat shading, but that didn't give me the look I wanted. I tried using a uniform vec3 colors and indexing it with gl_VertexID or gl_InstanceID (I'm not entirely sure the difference), but I couldn't get the arrays to compile.
Here is the github repo, by the way.
flat qualified fragment shader inputs will receive the same value for the same primitive. In your case, a triangle.
Of course, a triangle is composed of 3 vertices. And if the vertex shaders output 3 different values, how does the fragment shader know which value to get?
This comes down to what is called the "provoking vertex." When you render, you specify a particular primitive to use in your glDraw* call (GL_TRIANGLE_STRIP, GL_TRIANGLES, etc). These primitive types will generate a number of base primitives (ie: single triangle), based on how many vertices you provided.
When a base primitive is generated, one of the vertices in that base primitive is said to be the "provoking vertex". It is that vertex's data that is used for all flat parameters.
The reason you're seeing what you are seeing is because the two adjacent triangles just happen to be using the same provoking vertex. Your mesh is smooth, so two adjacent triangles share 2 vertices. Your mesh generation just so happens to be generating a mesh such that the provoking vertex for each triangle is shared between them. Which means that the two triangles will get the same flat value.
You will need to adjust your index list or otherwise alter your mesh generation so that this doesn't happen. Or you can just divide your mesh into individual triangles; that's probably much easier.
As a final resort, I just duplicated the vertices, and it seems to work. I haven't been able to profile it to see if it makes a big performance drop. I'd be open to any other suggestions!
for (int z = 0; z < height; z++) {
for (int x = 0; x < width; x++) {
// scale from [-1, 1] to [minY, maxY]
float heightY = (float) ((noise.getNoise(x * xStep * spikeness, z * zStep * spikeness) + 1f) / 2
* (maxY - minY) + minY);
positions.add(START_X + x * xStep);
positions.add(heightY);
positions.add(START_Z + z * zStep);
positions.add(START_X + x * xStep);
positions.add(heightY);
positions.add(START_Z + z * zStep);
}
}
for (int z = 0; z < height - 1; z++) {
for (int x = 0; x < width - 1; x++) {
int leftTop = z * width + x;
int leftBottom = (z + 1) * width + x;
int rightBottom = (z + 1) * width + x + 1;
int rightTop = z * width + x + 1;
indices.add(2 * leftTop);
indices.add(2 * leftBottom);
indices.add(2 * rightTop);
indices.add(2 * rightTop + 1);
indices.add(2 * leftBottom + 1);
indices.add(2 * rightBottom + 1);
}
}
EDIT: NEW CODE AND OUTPUT AFTER DASHED LINE
This is for a school assignment but I just can't find anything that will rid me of this problem. What the program is suppose to do is take a GeneralPath object and create a Shape3D object with it using a class called RotatedShape. It has a constructor (the only one needed for the project) that takes the GeneralPath as a parameter. With this, the path is meant to be rotated around an axis to display a solid shape, similar to a Torus. The code is based off of code from the textbook I'm using, as most projects in the class usually are.
The exception happens here: qa.setCoordinates(i * m, ptsList); which is in the RotatedShape class, near the bottom. I know the problem is coming from using ptsList as a parameter because earlier I was having the same problem with that Point3d array when initializing it, hence why its size is currently set to 100 as a placeholder.
When run, the GUI displays nothing and I get this in my console output window:
x = 0.1 y = -0.5
Exception in thread "Thread-2" java.lang.NullPointerException
at javax.media.j3d.GeometryArrayRetained.setCoordinates(GeometryArrayRetained.java:3849)
at javax.media.j3d.GeometryArrayRetained.setCoordinates(GeometryArrayRetained.java:3849)
at javax.media.j3d.GeometryArray.setCoordinates(GeometryArray.java:1469)
at RotatedShape.<init>(Project8.java:202)
at Project8.createSceneGraph(Project8.java:58)
at Project8.init(Project8.java:27)
at com.sun.j3d.utils.applet.MainFrame.run(MainFrame.java:267)
at java.lang.Thread.run(Thread.java:724)
BUILD SUCCESSFUL (total time: 8 seconds)
I can clearly see where the error is occurring and I have an idea as to what the problem is, but I have no idea how to go about fixing it. It's probably something stupid about initializing the array or something, but I can't seem to find anything that helps.
Below is the code that is all in one file, as the professor wants it.
import javax.vecmath.*;
import java.awt.*;
import java.awt.event.*;
import javax.media.j3d.*;
import com.sun.j3d.utils.universe.*;
import com.sun.j3d.utils.geometry.*;
import java.applet.*;
import com.sun.j3d.utils.applet.MainFrame;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.PathIterator;
import java.util.Vector;
public class Project8 extends Applet {
public static void main(String[] args) {
new MainFrame(new Project8(), 640, 480);
}
public void init() {
// create canvas
GraphicsConfiguration gc
= SimpleUniverse.getPreferredConfiguration();
Canvas3D cv = new Canvas3D(gc);
setLayout(new BorderLayout());
add(cv, BorderLayout.CENTER);
BranchGroup bg = createSceneGraph();
bg.compile();
SimpleUniverse su = new SimpleUniverse(cv);
su.getViewingPlatform().setNominalViewingTransform();
su.addBranchGraph(bg);
}
private BranchGroup createSceneGraph() {
BranchGroup root = new BranchGroup();
TransformGroup spin = new TransformGroup();
spin.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
root.addChild(spin);
Transform3D tr = new Transform3D();
tr.setScale(0.8);
tr.setRotation(new AxisAngle4d(1, 0, 0, Math.PI / 6));
TransformGroup tg = new TransformGroup(tr);
spin.addChild(tg);
GeneralPath path = new GeneralPath();
path.moveTo(0.1f, -0.5f);
path.quadTo(0.5f, 1, 0.8f, 0.5f);
path.lineTo(1, 0.2f);
path.closePath();
Shape3D shape = new RotatedShape(path);
Appearance ap = new Appearance();
ap.setMaterial(new Material());
shape.setAppearance(ap);
tg.addChild(shape);
Alpha alpha = new Alpha(-1, 8000);
RotationInterpolator rotator = new RotationInterpolator(alpha, spin);
BoundingSphere bounds = new BoundingSphere();
rotator.setSchedulingBounds(bounds);
spin.addChild(rotator);
// background and lights
Background background = new Background(1.0f, 1.0f, 1.0f);
background.setApplicationBounds(bounds);
root.addChild(background);
AmbientLight light = new AmbientLight(true, new Color3f(Color.blue));
light.setInfluencingBounds(bounds);
root.addChild(light);
PointLight ptlight = new PointLight(new Color3f(Color.white),
new Point3f(3f, 3f, 3f), new Point3f(1f, 0f, 0f));
ptlight.setInfluencingBounds(bounds);
root.addChild(ptlight);
return root;
}
}
class RotatedShape extends Shape3D {
public RotatedShape(GeneralPath path) {
int depth = 100;
PathIterator iter = path.getPathIterator(new AffineTransform());
Point3d[] ptsList = new Point3d[depth];
float[] seg = new float[6];
float x = 0, y = 0;
float x0 = 0, y0 = 0;
int pos = 0;
while (!iter.isDone()) {
int segType = iter.currentSegment(seg);
switch (segType) {
case PathIterator.SEG_MOVETO:
x = x0 = seg[0];
y = y0 = seg[1];
System.out.println("x = " + x + " y = " + y);
ptsList[pos] = new Point3d(x, y, 0);
pos++;
break;
case PathIterator.SEG_LINETO:
x = seg[0];
y = seg[1];
ptsList[pos] = new Point3d(x, y, 0);
pos++;
break;
case PathIterator.SEG_QUADTO:
for (int i = 1; i < 10; i++) {
float t = (float) i / 10f;
float xi = (1 - t) * (1 - t) * x + 2 * t * (1 - t) * seg[0] + t * t * seg[2];
float yi = (1 - t) * (1 - t) * y + 2 * t * (1 - t) * seg[1] + t * t * seg[3];
ptsList[pos] = new Point3d(xi, yi, 0);
pos++;
}
x = seg[2];
y = seg[3];
ptsList[pos] = new Point3d(x, y, 0);
pos++;
break;
case PathIterator.SEG_CUBICTO:
for (int i = 1; i < 20; i++) {
float t = (float) i / 20f;
float xi = (1 - t) * (1 - t) * (1 - t) * x + 3 * t * (1 - t) * (1 - t) * seg[0]
+ 3 * t * t * (1 - t) * seg[2] + t * t * t * seg[4];
float yi = (1 - t) * (1 - t) * (1 - t) * y + 3 * t * (1 - t) * (1 - t) * seg[1]
+ 3 * t * t * (1 - t) * seg[3] + t * t * t * seg[5];
ptsList[pos] = new Point3d(xi, yi, 0);
pos++;
}
x = seg[2];
y = seg[3];
ptsList[pos] = new Point3d(x, y, 0);
pos++;
break;
case PathIterator.SEG_CLOSE:
x = x0;
y = y0;
ptsList[pos] = new Point3d(x, y, 0);
pos++;
break;
}
iter.next();
}
int m = 20;
//int n = 40;
int n = ptsList.length;
Transform3D rot2 = new Transform3D();
rot2.rotY(2.0 * Math.PI / n);
IndexedQuadArray qa = new IndexedQuadArray(m * n,
IndexedQuadArray.COORDINATES, 4 * m * n);
int quadIndex = 0;
for (int i = 0; i < n; i++) {
qa.setCoordinates(i * m, ptsList);
for (int j = 0; j < m; j++) {
rot2.transform(ptsList[j]);
int[] quadCoords = {i * m + j, ((i + 1) % n) * m + j,
((i + 1) % n) * m + ((j + 1) % m), i * m + ((j + 1) % m)};
qa.setCoordinateIndices(quadIndex, quadCoords);
quadIndex += 4;
}
}
GeometryInfo gi = new GeometryInfo(qa);
NormalGenerator ng = new NormalGenerator();
ng.generateNormals(gi);
this.setGeometry(gi.getGeometryArray());
}
}
import javax.vecmath.*;
import java.awt.*;
import java.awt.event.*;
import javax.media.j3d.*;
import com.sun.j3d.utils.universe.*;
import com.sun.j3d.utils.geometry.*;
import java.applet.*;
import com.sun.j3d.utils.applet.MainFrame;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.PathIterator;
import java.util.Vector;
public class Project8 extends Applet {
public static void main(String[] args) {
new MainFrame(new Project8(), 640, 480);
}
public void init() {
// create canvas
GraphicsConfiguration gc
= SimpleUniverse.getPreferredConfiguration();
Canvas3D cv = new Canvas3D(gc);
setLayout(new BorderLayout());
add(cv, BorderLayout.CENTER);
BranchGroup bg = createSceneGraph();
bg.compile();
SimpleUniverse su = new SimpleUniverse(cv);
su.getViewingPlatform().setNominalViewingTransform();
su.addBranchGraph(bg);
}
private BranchGroup createSceneGraph() {
BranchGroup root = new BranchGroup();
TransformGroup spin = new TransformGroup();
spin.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
root.addChild(spin);
Transform3D tr = new Transform3D();
tr.setScale(0.8);
tr.setRotation(new AxisAngle4d(1, 0, 0, Math.PI / 6));
TransformGroup tg = new TransformGroup(tr);
spin.addChild(tg);
GeneralPath path = new GeneralPath();
path.moveTo(0.1f, -0.5f);
path.quadTo(0.5f, 1, 0.8f, 0.5f);
path.lineTo(1, 0.2f);
path.closePath();
Shape3D shape = new RotatedShape(path);
Appearance ap = new Appearance();
ap.setMaterial(new Material());
shape.setAppearance(ap);
tg.addChild(shape);
Alpha alpha = new Alpha(-1, 8000);
RotationInterpolator rotator = new RotationInterpolator(alpha, spin);
BoundingSphere bounds = new BoundingSphere();
rotator.setSchedulingBounds(bounds);
spin.addChild(rotator);
// background and lights
Background background = new Background(1.0f, 1.0f, 1.0f);
background.setApplicationBounds(bounds);
root.addChild(background);
AmbientLight light = new AmbientLight(true, new Color3f(Color.blue));
light.setInfluencingBounds(bounds);
root.addChild(light);
PointLight ptlight = new PointLight(new Color3f(Color.white),
new Point3f(3f, 3f, 3f), new Point3f(1f, 0f, 0f));
ptlight.setInfluencingBounds(bounds);
root.addChild(ptlight);
return root;
}
}
class RotatedShape extends Shape3D {
public RotatedShape(GeneralPath path) {
int depth = 100;
PathIterator iter = path.getPathIterator(new AffineTransform());
Vector ptsVector = new Vector();
float[] seg = new float[6];
float x = 0, y = 0;
float x0 = 0, y0 = 0;
int pos = 0;
while (!iter.isDone()) {
int segType = iter.currentSegment(seg);
switch (segType) {
case PathIterator.SEG_MOVETO:
x = x0 = seg[0];
y = y0 = seg[1];
ptsVector.add(new Point3d(x, y, 0));
pos++;
break;
case PathIterator.SEG_LINETO:
x = seg[0];
y = seg[1];
ptsVector.add(new Point3d(x, y, 0));
pos++;
break;
case PathIterator.SEG_QUADTO:
for (int i = 1; i < 10; i++) {
float t = (float) i / 10f;
float xi = (1 - t) * (1 - t) * x + 2 * t * (1 - t) * seg[0] + t * t * seg[2];
float yi = (1 - t) * (1 - t) * y + 2 * t * (1 - t) * seg[1] + t * t * seg[3];
ptsVector.add(new Point3d(xi, yi, 0));
pos++;
}
x = seg[2];
y = seg[3];
ptsVector.add(new Point3d(x, y, 0));
pos++;
break;
case PathIterator.SEG_CUBICTO:
for (int i = 1; i < 20; i++) {
float t = (float) i / 20f;
float xi = (1 - t) * (1 - t) * (1 - t) * x + 3 * t * (1 - t) * (1 - t) * seg[0]
+ 3 * t * t * (1 - t) * seg[2] + t * t * t * seg[4];
float yi = (1 - t) * (1 - t) * (1 - t) * y + 3 * t * (1 - t) * (1 - t) * seg[1]
+ 3 * t * t * (1 - t) * seg[3] + t * t * t * seg[5];
ptsVector.add(new Point3d(xi, yi, 0));
pos++;
}
x = seg[2];
y = seg[3];
ptsVector.add(new Point3d(x, y, 0));
pos++;
break;
case PathIterator.SEG_CLOSE:
x = x0;
y = y0;
ptsVector.add(new Point3d(x, y, 0));
pos++;
break;
}
iter.next();
}
for (int i = 0; i < ptsVector.size(); i++)
System.out.println("Vector = " + ptsVector.elementAt(i) + " at " + i);
System.out.println("pos = " + pos);
Point3d[] ptsArray = null;
for (int i = 0; i < ptsVector.size(); i++) {
ptsArray[i] = (Point3d) ptsVector.elementAt(i);
}
// Point3d[] ptsArray = ptsVector.toArray(new Point3d(ptsVector.size()));
int m = 20;
//int n = 40;
int n = ptsArray.length;
Transform3D rot2 = new Transform3D();
rot2.rotY(2.0 * Math.PI / n);
IndexedQuadArray qa = new IndexedQuadArray(m * n,
IndexedQuadArray.COORDINATES, 4 * m * n);
int quadIndex = 0;
for (int i = 0; i < n; i++) {
System.out.println("i = " + i);
qa.setCoordinates(i * m, ptsArray);
for (int j = 0; j < m; j++) {
rot2.transform(ptsArray[j]);
int[] quadCoords = {i * m + j, ((i + 1) % n) * m + j,
((i + 1) % n) * m + ((j + 1) % m), i * m + ((j + 1) % m)};
qa.setCoordinateIndices(quadIndex, quadCoords);
quadIndex += 4;
}
}
GeometryInfo gi = new GeometryInfo(qa);
NormalGenerator ng = new NormalGenerator();
ng.generateNormals(gi);
this.setGeometry(gi.getGeometryArray());
}
}
Output:
run:
Vector = (0.10000000149011612, -0.5, 0.0) at 0
Vector = (0.17899999022483826, -0.2199999839067459, 0.0) at 1
Vector = (0.25600001215934753, 0.020000001415610313, 0.0) at 2
Vector = (0.3310000002384186, 0.2200000286102295, 0.0) at 3
Vector = (0.40400004386901855, 0.3800000250339508, 0.0) at 4
Vector = (0.4750000238418579, 0.5, 0.0) at 5
Exception in thread "Thread-2" java.lang.NullPointerException
Vector = (0.5440000295639038, 0.5800000429153442, 0.0) at 6
at RotatedShape.<init>(Project8.java:197)
Vector = (0.6110000014305115, 0.6200000047683716, 0.0) at 7
Vector = (0.6759999990463257, 0.6200000047683716, 0.0) at 8
Vector = (0.7389999628067017, 0.5800000429153442, 0.0) at 9
Vector = (0.800000011920929, 0.5, 0.0) at 10
Vector = (1.0, 0.20000000298023224, 0.0) at 11
Vector = (0.10000000149011612, -0.5, 0.0) at 12
pos = 13
at Project8.createSceneGraph(Project8.java:58)
at Project8.init(Project8.java:27)
at com.sun.j3d.utils.applet.MainFrame.run(MainFrame.java:267)
at com.sun.j3d.utils.applet.MainFrame.run(MainFrame.java:267)
at java.lang.Thread.run(Thread.java:724)
I have coded a heightmap but it seems to lag the client. I just don't know how to increase the fps. I get about 3-6fps with the heightmap. Im using a quite large bmp for the heightmap, I think its 1024x1024. When i use a smaller on its fine, maybe im just not using the code effectively. Is there a better way to code this heightmap or did I just code it wrong. It is my first time I have worked on a heightmap. Thanks
public class HeightMap {
private final float xScale, yScale, zScale;
private float[][] heightMap;
private FloatBuffer vertices, normals, texCoords;
private IntBuffer indices;
private Vector3f[] verticesArray, normalsArray;
private int[] indicesArray;
private int width;
private int height;
public float getHeight(int x, int y) {
return heightMap[x][y] * yScale;
}
public HeightMap(String path, int resolution) {
heightMap = loadHeightmap("heightmap.bmp");
xScale = 1000f / resolution;
yScale = 8;
zScale = 1000f / resolution;
verticesArray = new Vector3f[width * height];
vertices = BufferUtils.createFloatBuffer(3 * width * height);
texCoords = BufferUtils.createFloatBuffer(2 * width * height);
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
final int pos = height * x + y;
final Vector3f vertex = new Vector3f(xScale * x, yScale * heightMap[x][y], zScale * y);
verticesArray[pos] = vertex;
vertex.store(vertices);
texCoords.put(x / (float) width);
texCoords.put(y / (float) height);
}
}
vertices.flip();
texCoords.flip();
normalsArray = new Vector3f[height * width];
normals = BufferUtils.createFloatBuffer(3 * width * height);
final float xzScale = xScale;
for (int x = 0; x < width; ++x) {
for (int y = 0; y < height; ++y) {
final int nextX = x < width - 1 ? x + 1 : x;
final int prevX = x > 0 ? x - 1 : x;
float sx = heightMap[nextX][y] - heightMap[prevX][y];
if (x == 0 || x == width - 1) {
sx *= 2;
}
final int nextY = y < height - 1 ? y + 1 : y;
final int prevY = y > 0 ? y - 1 : y;
float sy = heightMap[x][nextY] - heightMap[x][prevY];
if (y == 0 || y == height - 1) {
sy *= 2;
}
final Vector3f normal = new Vector3f(-sx * yScale, 2 * xzScale, sy * yScale).normalise(null);
normalsArray[height * x + y] = normal;
normal.store(normals);
}
}
normals.flip();
indicesArray = new int[6 * (height - 1) * (width - 1)];
indices = BufferUtils.createIntBuffer(6 * (width - 1) * (height - 1));
for (int i = 0; i < width - 1; i++) {
for (int j = 0; j < height - 1; j++) {
int pos = (height - 1) * i + j;
indices.put(height * i + j);
indices.put(height * (i + 1) + j);
indices.put(height * (i + 1) + (j + 1));
indicesArray[6 * pos] = height * i + j;
indicesArray[6 * pos + 1] = height * (i + 1) + j;
indicesArray[6 * pos + 2] = height * (i + 1) + (j + 1);
indices.put(height * i + j);
indices.put(height * i + (j + 1));
indices.put(height * (i + 1) + (j + 1));
indicesArray[6 * pos + 3] = height * i + j;
indicesArray[6 * pos + 4] = height * i + (j + 1);
indicesArray[6 * pos + 5] = height * (i + 1) + (j + 1);
}
}
indices.flip();
}
private float[][] loadHeightmap(String fileName) {
try {
BufferedImage img = ImageIO.read(ResourceLoader.getResourceAsStream(fileName));
width = img.getWidth();
height = img.getHeight();
float[][] heightMap = new float[width][height];
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
heightMap[x][y] = 0xFF & img.getRGB(x, y);
}
}
return heightMap;
} catch (IOException e) {
System.out.println("Nincs meg a heightmap!");
return null;
}
}
public void render() {
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glNormalPointer(0, normals);
glVertexPointer(3, 0, vertices);
glTexCoordPointer(2, 0, texCoords);
glDrawElements(GL_TRIANGLE_STRIP, indices);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
}
}
Sorry to bring up an old topic, however i see a lot of people ask this:
Use a display list, instead of re-making the heightmap every time.
TheCodingUniverse has a good tutorial on how to do this.