I created a class with a method drawSphere to replace glutDrawSolidSphere. See code below.
But I wonder, how do I wrap a texture around it without tiling? For example, if I want to draw a mouth, eyes and a nose on it, then I want it to have only one mouth, two eyes and one nose, and not 100 tiled all over the sphere.
I'm using Jogl with some libraries.
class Shape {
public void drawSphere(double radius, int slices, int stacks) {
gl.glEnable(GL_TEXTURE_2D);
head.bind(gl); //This method is a shorthand equivalent of gl.glBindTexture(texture.getTarget(), texture.getTextureObject());
gl.glBegin(GL_QUADS);
double stack = (2*PI)/stacks;
double slice = (2*PI)/slices;
for (double theta = 0; theta < 2 * PI; theta += stack) {
for (double phi = 0; phi < 2 * PI; phi += slice) {
Vector p1 = getPoints(phi, theta, radius);
Vector p2 = getPoints(phi + slice, theta, radius);
Vector p3 = getPoints(phi + slice, theta + stack, radius);
Vector p4 = getPoints(phi, theta + stack, radius);
gl.glTexCoord2d(0, 0);
gl.glVertex3d(p1.x(), p1.y(), p1.z());
gl.glTexCoord2d(1, 0);
gl.glVertex3d(p2.x(), p2.y(), p2.z());
gl.glTexCoord2d(1, 1);
gl.glVertex3d(p3.x(), p3.y(), p3.z());
gl.glTexCoord2d(0, 1);
gl.glVertex3d(p4.x(), p4.y(), p4.z());
}
}
gl.glEnd();
gl.glDisable(GL_TEXTURE_2D);
}
Vector getPoints(double phi, double theta, double radius) {
double x = radius * cos(theta) * sin(phi);
double y = radius * sin(theta) * sin(phi);
double z = radius * cos(phi);
return new Vector(x, y, z);
}
}
You could just map latitude and longitude directly to the texture co-ordinates.
for (double theta = 0; theta < 2 * PI; theta += stack) {
for (double phi = 0; phi < 2 * PI; phi += slice) {
Just scale theta and phi to be between 0 and 1.
double s0 = theta / (2 * PI);
double s1 = (theta + stack) / (2 * PI);
double t0 = phi / (2 * PI);
double t1 = (phi + slice) / (2 * PI);
And use s0,s1,t0,t1 in place of 0 and 1 in your texCoord() calls.
Related
I have to points in 3D space that I want to draw a cylinder between. I currently have this code:
applet.pushMatrix();
applet.stroke(0);
applet.fill(0);
applet.line(this.start.x, this.start.y, this.start.z, this.end.x, this.end.y, this.end.z); //debug, shows where the cylinder should be
applet.translate(this.start.x, this.start.y);
applet.beginShape(PConstants.TRIANGLE_STRIP);
float xdif = this.end.x - this.start.x;
float ydif = this.end.y - this.start.y;
float zdif = this.end.z - this.start.z;
float rx = (float)Math.atan(ydif / xdif);
float ry = (float)Math.atan(zdif / xdif);
float rz = (float)Math.atan(zdif == 0 ? 0 : ydif / zdif);
applet.rotateZ((float) (rx - Math.PI / 2));
applet.rotateY((float) (ry - Math.PI / 2));
applet.rotateX((float) (rz - Math.PI / 2));
float r = 20;
float len = HelperFunctions.distance(this.start, this.end) / 2;
boolean w = false;
for (int i = 0; i < 2; i += 1) {
for (float j = 0; j < Math.PI * 2 + 0.2; j += 0.4) {
w = !w;
float z = (i + (w ? 0 : 1)) * len;
float x = (float)(r * Math.cos(j));
float y = (float)(r * Math.sin(j));
applet.vertex(y, x, z);
}
}
applet.endShape();
applet.popMatrix();
The cylinder does draw correctly, however, it doesn't rotate correctly. I'm trying to use trig to determine the rotation angles, however, I'm not sure I've done it correctly. How would I get the correct angles to rotate around such that it is drawn from Vector start to Vector end?
Vector is a custom class with just a float x, y, z, and HelperFunctions.distance takes two Vectors and calculates the distance (pythagoras).
Thanks in advance.
I want to change the color of the strokes but I can't figure out how to do this correctly I looked up a tutorial and it showed me the hu stuff in the code. That it changes the hu in the for loop but it just remains one color.. In my case yellowish
void setup(){
size(500,500);
colorMode(HSB);
}
float t = 0;
float tn = 0;
void draw(){
background(0);
translate(width / 2, height / 2);
noFill();
stroke(255);
strokeWeight(2);
float hu = 0;
beginShape();
//add vertices...
for(float theta = 0; theta <= 8 * PI; theta += 0.001){
float rad = r(theta,
1, //a
1, //b
sin(tn) * 0.1 + 5, //m
cos(tn) / 2, //n1
sin(t) * 0.5 + 0.5, //n2
cos(t) * 0.5 + 0.5 //n3
);
float x = rad * cos(theta) * 50;
float y = rad * sin(theta) * 50;
stroke(hu, 255, 255);
vertex(x,y);
hu += 1;
if(hu > 255){
hu = 0;
}
}
endShape();
t += 0.1;
tn += 0.1;
}
float r(float theta, float a, float b, float m, float n1, float n2, float n3){
return pow(pow(abs(cos(m * theta / 4.0) / a), n2) +
pow(abs(sin(m * theta / 4.0) / b), n3), -1.0 / n1) ;
}
Please consult the Processing reference for the beginShape function:
The P2D and P3D renderers allow stroke() and fill() to be altered on a per-vertex basis, but the default renderer does not.
In other words, you can't change the stroke color like this with the default renderer. You could just use the P2D renderer instead:
size(500, 500, P2D);
If you need to use the default renderer for some reason, then you're going to have to draw the lines yourself instead of relying on the vertex function.
I'm working on a game where you are a spaceship. This spaceship has to be able to rotate. The rectangle has two arrays x[], y[] containing all the corners positions of the rectangle. But when I apply the rotation formula, I get a rather wierd rotation. To try to explain it, it looks like it's rotating the bottom left of the screen.
To make these corner arrays i take in an x position, y position, width and height.
Making of the corner-arrays
public Vertex2f(float x, float y, float w, float h){
this.x[0] = x;
this.y[0] = y;
this.x[1] = x+w;
this.y[1] = y;
this.x[2] = x+w;
this.y[2] = y+h;
this.x[3] = x;
this.y[3] = y+h;
}
My rotation function
public void rotate(float angle){
this.rotation = angle;
double cos = Math.cos(rotation);
double sin = Math.sin(rotation);
for(int i = 0; i < x.length; i++){
x[i] = (float)(cos * x[i] - sin * y[i]);
y[i] = (float)(sin * x[i] + cos * y[i]);
}
}
If it helps I am using LWJGL/OpenGL in java for all the graphics and Slick2d to load and init the sprites I am using.
Try this one:
public void rotate(float angle){
this.rotation = angle;
double cos = Math.cos(rotation);
double sin = Math.sin(rotation);
double xOffset = (x[0]+x[2])/2;
double yOffset = (y[0]+y[2])/2;
for(int i = 0; i < 3; i++){
x[i] = (float)(cos * (x[i]-xOffset) - sin * (y[i]-yOffset)) + xOffset;
y[i] = (float)(sin * (x[i]-xOffset) + cos * (y[i]-yOffset)) + yOffset;
}
}
you have to rotate around center of your rectangle. Otherwise center is in x=0 and y=0
edited:
public void rotate(float angle){
this.rotation = angle;
double cos = Math.cos(rotation);
double sin = Math.sin(rotation);
double xOffset = (x[0]+x[2])/2;
double yOffset = (y[0]+y[2])/2;
for(int i = 0; i < 3; i++){
double newX = (float)(cos * (x[i]-xOffset) - sin * (y[i]-yOffset)) + xOffset;
double newY = (float)(sin * (x[i]-xOffset) + cos * (y[i]-yOffset)) + yOffset;
x[i] = newX;
y[i] = newY;
}
}
see other thread
The problem with the formulas
x[i] = (float)(cos * x[i] - sin * y[i]);
y[i] = (float)(sin * x[i] + cos * y[i]);
apart from the missing rotation center is that you change x[i] in the first formula but expect to use the original value in the second formula. Thus you need to use local variables lx, ly as in
float lx = x[i] - xcenter;
float ly = y[i] - ycenter;
x[i] = xcenter + (float)(cos * lx - sin * ly);
y[i] = ycenter + (float)(sin * lx + cos * ly);
If the object already is rotated with an angle of rotation, then this code adds the angle angle to the total rotation angle. If instead the given argument angle is to be the new total rotation angle, then the sin and cos values need to be computed with the angle difference. That is, start the procedure with, for instance,
public void rotate(float angle){
double cos = Math.cos(angle - rotation);
double sin = Math.sin(angle - rotation);
this.rotation = angle;
(Question is at bottom)Im learning opengl(using lwjgl) and done some drawing of flat shape through sending buffers. Now I need to draw many spheres in single buffer. In my last question, I was advised to use geometry instancing but I dont know how to use any shader language in java yet so I'm trying to make multiple objects in single buffer just like in the examples.
What I tried to generate two spheres by QUAD_STRIP style(using lwjgl's own GLU.Sphere() function to fill the buffers):
n=c1*(c2+1);
float rr=(float) Math.random();
float gg=(float) Math.random();
float bb=(float) Math.random();
float aa=(float) Math.random();
positions = new float[c1 * (c2+1) * 3*2 *2];
normals = new float[c1 * (c2+1) * 3*2 *2];
colors = new float[c1 * (c2+1) * 4*2 *2];
int counter=0;
float drho = 3.141593F / 32.0f;
float dtheta = 6.283186F / 32.0f;
float ds = 1.0F / 32.0f;
float dt = 1.0F / 32.0f;
float t = 1.0F;
/*first sphere*/
for (int i = 0; i < 32; i++) {
float rho = i * drho;
float s = 0.0F;
for (int j = 0; j <= 32; j++) {
float theta = j == 32 ? 0.0F : j * dtheta;
float x = (float) (-Math.sin(theta) * Math.sin(rho));
float y = (float) (Math.cos(theta) * Math.sin(rho));
float z = (float) (1.0f * Math.cos(rho));
normals[counter*3+0]=x*1.0f;normals[counter*3+1]=y*1.0f;normalscounter*3+2]=z*1.0f;
colors[counter*4+0]=rr;colors[counter*4+1]=gg;colors[counter*4+2]=bb;colors[counter*4+3]=1.0f/*aa*/;
positions[counter*3+0]=x*r;positions[counter*3+1]=y*r;positions[counter*3+2]=z*r;
counter++;
x = (float) (-Math.sin(theta) * Math.sin(rho + drho));
y = (float) (Math.cos(theta) * Math.sin(rho + drho));
z = (float) (1.0f * Math.cos(rho + drho));
normals[counter*3+0]=x*1.0f;normals[counter*3+1]=y*1.0f;normals[counter*3+2]=z*1.0f;
colors[counter*4+0]=rr;colors[counter*4+1]=gg;colors[counter*4+2]=bb;colors[counter*4+3]=1.0f/*aa*/;
positions[counter*3+0]=x*r;positions[counter*3+1]=y*r;positions[counter*3+2]=z*r;
counter++;
s += ds;
}
t -= dt;
}
/* first sphere end */
/* second sphere generation */
{
drho = 3.141593F / 32.0f;
dtheta = 6.283186F / 32.0f;
ds = 1.0F / 32.0f;
dt = 1.0F / 32.0f;
t = 1.0F;
for (int i = 0; i < 32; i++) {
float rho = i * drho;
float s = 0.0F;
for (int j = 0; j <= 32; j++) {
float theta = j == 32 ? 0.0F : j * dtheta;
float x = (float) (-Math.sin(theta) * Math.sin(rho));
float y = (float) (Math.cos(theta) * Math.sin(rho));
float z = (float) (1.0f * Math.cos(rho));
normals[counter*3+0]=x*1.0f;normals[counter*3+1]=y*1.0f;normals[counter*3+2]=z*1.0f;
colors[counter*4+0]=rr;colors[counter*4+1]=gg;colors[counter*4+2]=bb;colors[counter*4+3]=1.0f/*aa*/;
positions[counter*3+0]=x*r+1.0f;positions[counter*3+1]=y*r+1.0f;positions[counter*3+2]=z*r+1.0f;
counter++;
x = (float) (-Math.sin(theta) * Math.sin(rho + drho));
y = (float) (Math.cos(theta) * Math.sin(rho + drho));
z = (float) (1.0f * Math.cos(rho + drho));
normals[counter*3+0]=x*1.0f;normals[counter*3+1]=y*1.0f;normals[counter*3+2]=z*1.0f;
colors[counter*4+0]=rr;colors[counter*4+1]=gg;colors[counter*4+2]=bb;colors[counter*4+3]=1.0f/*aa*/;
positions[counter*3+0]=x*r+1.0f;positions[counter*3+1]=y*r+1.0f;positions[counter*3+2]=z*r+1.0f;
counter++;
s += ds;
}
t -= dt;
}
}
/*second sphere end*/
positionsBuf=BufferUtils.createFloatBuffer(c1 * (c2+1) * 3*2 *2);
positionsBuf.put(positions);
positionsBuf.rewind();
colorsBuf=BufferUtils.createFloatBuffer(c1 * (c2+1) * 4*2 *2);
colorsBuf.put(colors);
colorsBuf.rewind();
normalsBuf=BufferUtils.createFloatBuffer(c1 * (c2+1) * 3*2 *2);
normalsBuf.put(normals);
normalsBuf.rewind();
As you can see, below image shows how two spheres are drawn. There is an unwanted link between two.
Most probably the rope is caused by the last point of first sphere and first point of second sphere. Is there some kind of delimiter/drawing-hint to separate two drawings in the same buffer?
Here is how they are drawn:
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER,sphereBufferCol.get(0));
GL11.glColorPointer(4, GL11.GL_FLOAT, 0, 0);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, sphereBufferPos.get(0));
GL11.glVertexPointer(3, GL11.GL_FLOAT, 0, 0);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, sphereBufferNormal.get(0));
GL11.glNormalPointer(GL11.GL_FLOAT, 0, 0);
GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY);
GL11.glEnableClientState(GL11.GL_COLOR_ARRAY);
GL11.glEnableClientState(GL11.GL_NORMAL_ARRAY);
//Each sphere is generated 32 by 32 quadstriparray and each having two sets of two points and there are two spheres
GL11.glDrawArrays(GL11.GL_QUAD_STRIP, 0, 32*33*2 *2);
GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY);
GL11.glDisableClientState(GL11.GL_COLOR_ARRAY);
GL11.glDisableClientState(GL11.GL_NORMAL_ARRAY);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
Question: How can I make that rope-like thing disappear without decreasing performance? Maybe putting zero to last and first points' alpha value can make it invisible but wouldnt that cause two holes on each sphere and decrease performance because of many lines on the screen?
All vertex values will be altered by opencl interoperability so single drawing call is needed to draw whole 10000+ spheres.
There seem to be a number of options:
use multiple buffers
use quads instead of quad strips
use primitive restart
use degenerate triangles, i.e. add the last vertex twice
use [instanced rendering] (http://www.opengl.org/wiki/Vertex_Rendering#Instancing)
If you are on newer hardware and want to use quad strips, I'd prefer using primitive restart.
Please note that this is just the result of a quick assessment and anchecked (I personally don't use quad strips or even tri strips that often ;) ).
I am having an issue with my program; currently it rotates around a set point, and can rotate models around it. Of course, this is a problem as I want it to be a first-person perspective, and currently, it rotates around a point in front of the viewer, instead of the perspective of the viewer. Here is the trigonometric calculations:
protected void drawWireframe(Graphics g) {
double theta = Math.PI * -azimuth / 180.0D;
double phi = Math.PI * elevation / 180.0D;
float cosT = (float) Math.cos(theta);
float sinT = (float) Math.sin(theta);
float cosP = (float) Math.cos(phi);
float sinP = (float) Math.sin(phi);
float cosTcosP = cosT * cosP;
float cosTsinP = cosT * sinP;
float sinTcosP = sinT * cosP;
float sinTsinP = sinT * sinP;
float near = 6.0F;
g.setColor(Color.black);
g.fillRect(0, 0, getWidth(), getHeight());
for (int i = 0; i < tiles.size(); i++) {
Point[] points = new Point[vertices.length];
for (int j = 0; j < points.length; j++) {
float x0 = -(tiles.get(i).getX() + xmod + vertices[j]
.getX());
float y0 = (tiles.get(i).getY() + ymod + vertices[j].getY());
float z0 = -(tiles.get(i).getZ() + zmod + vertices[j]
.getZ());
float x1 = cosT * x0 + sinT * z0;
float y1 = -sinTsinP * x0 + cosP * y0 + cosTsinP * z0;
float z1 = cosTcosP * z0 - sinTcosP * x0 - sinP * y0;
if (z1 + near > 0) {
x1 = x1 * near / (z1 + near);
y1 = y1 * near / (z1 + near);
points[j] = new Point((int) (Math.max(getWidth(),
getHeight()) / 2 - (Math.max(getWidth(),
getHeight()) / near) * x1), (int) (Math.max(
getWidth(), getHeight()) / 2 - (Math.max(
getWidth(), getHeight()) / near) * y1));
}
}
}
}
How would I go about moving the rotational point without actually modifying the xmod, ymod and zmod (these are used for movements like jumping, walking, running, crouching... etc)
I know how to figure out how to get the new x, y and z positions, I just don't know how to apply them; if I add them to the mods, it creates a weird loop-d-loop. If I add them to the x1, y1, z1's it doesn't cover the z not rotating from the perspective.
To change the rotation point, you effectively need three transforms:
Translate the coordinate system so that the rotation point becomes the origin.
Perform a rotation around the origin
Translate the coordinate system back again.
This can be factored a number of ways, but that's the basic priniciple: translate->rotate->translate.
The way you "move the rotation point" of an object is by translating the object so that the rotation point is at the origin; do the rotation; then translate the object back. All of this is done in memory, between frames - the user never actually sees the object moving to the origin and back.
By the way, all this stuff is significantly easier if you understand vectors and matrix transformations - as you've seen yourself, without them the code can get out of hand.
Using vectors/matrices, all your code above could be reduced to only a few lines.