OpenGL ES 2.0 Android - Triangle color definition - opengl-es-2.0

I'm doing a tutorial on OpenGL ES for Android located here
My question is about the colors of the triangles. Take this triangle for example:
// This triangle is red, green, and blue.
final float[] triangle1VerticesData = {
// X, Y, Z,
// R, G, B, A
-0.5f, -0.25f, 0.0f,
*1.0f,* 0.0f, 0.0f, 1.0f,
0.5f, -0.25f, 0.0f,
0.0f, 0.0f, 1.0f, 1.0f,
0.0f, 0.559016994f, 0.0f,
0.0f, 1.0f, 0.0f, 1.0f};
at the first vertex why is red defined as 1.0f ? I was thinking it would be 255. Why is the total 1.0f ?
if i go to a site like this http://html-color-codes.info/ to get the color i want its showing in 255 toal not 1.0.

Colors in OpenGL are scaled in the range 0 to 1 (floating point). To convert 8bit color values (0 -255 integer) just divide the value by 255 and you will get the desired color.

This is the way colors are defined in OpenGL when specifying them with float values. The range of each component is 0.0 to 1.0.
Using a range of 0 to 255 makes sense when using byte values, because that's the range available in an unsigned 8-bit number.
Since floats don't cover a fixed range (*), the range used to define colors is somewhat arbitrary. Using 0.0 to 1.0 makes about as much sense as anything. You can look at the component values as fractions. For example, 0.0 for red means "no red", and 1.0 means "all available red". Using fractions to express values that go from "none" to "all" is very common, and values from 0.0 to 1.0 are the floating point representation of those fractions.
(*) There obviously is a range of values that can be represented by floats, but using the full range would not make sense in this context.

Related

Drawing a Speedometer with Core Graphics on OSX in NSView

I'm trying draw elements of a Speed Gauge using Core Graphics on OSX. I've almost got it but need a little bit of help on the center ticks inside of the gauge. Here is the image of what I'm trying to do:
Here is an image of what I've got so far:
I know how to draw the circle rings and how to draw segments based around the center of the gauge like this:
- (void)drawOuterGaugeRingsInRect:(CGContextRef)contextRef rect:(NSRect)rect {
CGContextSetLineWidth(contextRef,self.gaugeRingWidth);
CGContextSetStrokeColorWithColor(contextRef, [MyColors SpeedGaugeOuterRingGray].CGColor);
CGFloat startRadians = 0;
CGFloat endRadians = M_PI*2;
CGFloat radius = self.bounds.size.width/2 - 5;
CGContextAddArc(contextRef, CGRectGetMidX(rect),CGRectGetMidY(rect),radius,startRadians,endRadians,YES);
//Render the outer gauge
CGContextStrokePath(contextRef);
//Draw the inner gauge ring.
radius -= self.gaugeRingWidth;
CGContextSetStrokeColorWithColor(contextRef, [MyColors SpeedGaugeInnerRingGray].CGColor);
CGContextAddArc(contextRef, CGRectGetMidX(rect),CGRectGetMidY(rect),radius,startRadians,endRadians,YES);
//Render the inner gauge
CGContextStrokePath(contextRef);
radius -= self.gaugeRingWidth;
//Draw and fill the gauge background
CGContextSetFillColorWithColor(contextRef, [MyColors SpeedGaugeCenterFillBlack ].CGColor);
CGContextSetStrokeColorWithColor(contextRef, [MyColors SpeedGaugeCenterFillBlack].CGColor);
CGContextAddArc(contextRef, CGRectGetMidX(rect),CGRectGetMidY(rect),radius,startRadians,endRadians,YES);
//Render and fill the gauge background
CGContextDrawPath(contextRef, kCGPathFillStroke);
/*BLUE CIRCULAR DIAL */
//Prepare to draw the blue circular dial.
radius -= self.gaugeRingWidth/2;
//Adjust gauge ring width
CGContextSetLineWidth(contextRef,self.gaugeRingWidth/2);
CGContextSetStrokeColorWithColor(contextRef, [MyColors SpeedGaugeBlue].CGColor);
CGFloat startingRadians = [MyMathHelper degressToRadians:135];
CGFloat endingRadians = [MyMathHelper degressToRadians:45];
CGContextAddArc(contextRef, CGRectGetMidX(rect),CGRectGetMidY(rect),radius,startingRadians,endingRadians,NO);
//Render the blue gauge line
CGContextStrokePath(contextRef);
}
The code above is called in the drawRect: method in my NSView
The key section is the code here:
- (void)drawInnerDividerLines:(CGContextRef)context rect:(NSRect)rect {
CGFloat centerX = CGRectGetMidX(rect);
CGFloat centerY = CGRectGetMidY(rect);
CGContextSetLineWidth (context, 3.0);
CGContextSetRGBStrokeColor (context, 37.0/255.0, 204.0/255.0, 227.0/255.0, 0.5);
CGFloat destinationX = centerX + (centerY * (cos((135)*(M_PI/180))));
CGFloat destinationY = centerY + (centerX * (sin((135)*(M_PI/180))));
NSPoint destinationPoint = NSMakePoint(destinationX, destinationY);
CGContextMoveToPoint(context, centerX, centerY);
CGContextAddLineToPoint(context, destinationPoint.x, destinationPoint.y);
CGContextStrokePath(context);
}
I understand what is going on here but the problem I'm trying to solve is drawing the little lines, off of the inner blue line that extend toward the center point of the View, but do not draw all the way to the center. I'm a little unsure on how to modify the math and drawing logic to achieve this. Here is the unit circle I based the angles off of for Core Graphics Drawing.
The main problems I'm trying to solve are:
How to define the proper starting point off of the light blue inner line as a staring point for each gauge tick. Right now, I'm drawing the full line from the center to the edge of the gauge.
How to control the length of the tick gauge as it draws pointed toward the center off of it's origin point on the blue line.
Any tips or advice that would point in me in the right direction to solve this would be appreciated.
I recommend using vectors. You can find a line to any point on the circle given an angle by calculating:
dirX = cos(angle);
dirY = sin(angle);
startPt.x = center.x + innerRadius * dirX;
startPt.y = center.y + innerRadius * dirY;
endPt.x = center.x + outerRadius * dirX;
endPt.y = center.y + outerRadius * dirY;
You can then plot a line between startPt and endPt.
Any tips or advice that would point in me in the right direction to solve this would be appreciated.
Given a point on the circumference of your circle at a certain angle around the centre you can form a right angled triangle, the radius is the hypotenuse, and the other two sides being parallel to the x & y axes (ignore for a moment the degenerate case where the point is at 0, 90, 180 or 270 deg). Given that with the sin & cos formula (remember SOHCAHTOA from school) and some basic math you can calculate the coordinates of the point, and using that draw a radius from the centre to the point.
The end points of a "tick" mark just lie on circles of different radii, so the same math will give you the end points and you can draw the tick. You just need to decide the radii of these circles, i.e. the distance along your original radius the end points of the tick should be.
HTH
Another approach to avoid the trigonometry is to rotate the transformation matrix and just draw a vertical or horizontal line.
// A vertical "line" of width "width" along the y axis at x==0.
NSRect tick = NSMakeRect(-width / 2.0, innerRadius, width, outerRadius - innerRadius);
NSAffineTransform* xform = [NSAffineTransform transform];
// Move the x and y axes to the center of your speedometer so rotation happens around it
[xform translateXBy:center.x yBy:center.y];
// Rotate the coordinate system so that straight up is actually at your speedometer's 0
[xform rotateByDegrees:135];
[xform concat];
// Create a new transform to rotate back around for each tick.
xform = [NSAffineTransform transform];
[xform rotateByDegrees:-270.0 / numTicks];
for (int i = 0; i < numTicks; i++)
{
NSRectFill(tick);
[xform concat];
}
You probably want to wrap this in [NSGraphicsContext saveGraphicsState] and [NSGraphicsContext restoreGraphicsState] so the transformation matrix is restored when you're done.
If you want two different kinds of tick marks (major and minor), then have two different rects and select one based on i % 10 == 0 or whatever. Maybe also toggle the color. Etc.

Objective-c CATransform3DMakeRotation Clockwise/Counterclockwise

I'm rotating an UIView along the x axis using CATransform3DMakeRotation using the below code:
float radians = DegreesToRadians(30);
[UIView animateWithDuration:0.15 animations:^{
self.moveControlView.layer.transform = CATransform3DMakeRotation(radians,1,0,0);
}];
The rotation is applied always in the same versus (clockwise). I want to rotate the UIView in the opposite versus.
In order to achieve my goal I've tried:
Set a negative angle (-30)
Set the angle to 330
But the versus of the orientation doesn't change.
I have also try to set x = -1 leaving the angle positive.
Any suggestion?
You should apply a perspective to your transform, as it's explained in the similar question:
CATransform3D perspectiveTransform = CATransform3DIdentity;
perspectiveTransform.m34 = 1.0 / -500;
self.moveControlView.layer.transform =
CATransform3DRotate(perspectiveTransform, radians, 1.0f, 0.0f, 0.0f);;

Draw multiple objects with textures

I want to draw cubes using textures.
void OperateWithMainMatrix(ESContext* esContext, GLfloat offsetX, GLfloat offsetY, GLfloat offsetZ) {
UserData *userData = (UserData*) esContext->userData;
ESMatrix modelview;
ESMatrix perspective;
//Manipulation with matrix
...
glVertexAttribPointer(userData->positionLoc, 3, GL_FLOAT, GL_FALSE, 0, cubeFaces);
//in cubeFaces coordinates verticles cube
glVertexAttribPointer(userData->normalLoc, 3, GL_FLOAT, GL_FALSE, 0, cubeFaces);
//for normals (use in fragment shaider for textures)
glEnableVertexAttribArray(userData->positionLoc);
glEnableVertexAttribArray(userData->normalLoc);
// Load the MVP matrix
glUniformMatrix4fv(userData->mvpLoc, 1, GL_FALSE,
(GLfloat*)&userData->mvpMatrix.m[0][0]);
//Bind base map
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_CUBE_MAP, userData->baseMapTexId);
//Set the base map sampler to texture unit to 0
glUniform1i(userData->baseMapLoc, 0);
// Draw the cube
glDrawArrays(GL_TRIANGLES, 0, 36);
}
(coordinates transformation is in OperateWithMainMatrix() )
Then Draw() function is called:
void Draw(ESContext *esContext)
{
UserData *userData = esContext->userData;
// Set the viewport
glViewport(0, 0, esContext->width, esContext->height);
// Clear the color buffer
glClear(GL_COLOR_BUFFER_BIT);
// Use the program object
glUseProgram(userData->programObject);
OperateWithMainMatrix(esContext, 0.0f, 0.0f, 0.0f);
eglSwapBuffers(esContext->eglDisplay, esContext->eglSurface);
}
This work fine, but if I try to draw multiple cubes (next code for example):
void Draw(ESContext *esContext)
{ ...
// Use the program object
glUseProgram(userData->programObject);
OperateWithMainMatrix(esContext, 2.0f, 0.0f, 0.0f);
OperateWithMainMatrix(esContext, 1.0f, 0.0f, 0.0f);
OperateWithMainMatrix(esContext, 0.0f, 0.0f, 0.0f);
OperateWithMainMatrix(esContext, -1.0f, 0.0f, 0.0f);
OperateWithMainMatrix(esContext, -2.0f, 0.0f, 0.0f);
eglSwapBuffers(esContext->eglDisplay, esContext->eglSurface);
}
A side faces overlapes frontal face. This process is illustrated on image:
Alternate picture (with colours and clean image):
The side face of the right cube overlaps frontal face of the center cube.
How can i remove this effect and display miltiple cubes without it?
To fix this you need to utilize what's known as the depth buffer. This is what's responsible for making sure that surfaces don't get drawn overtop of surfaces that are nearer (like the side of a cube showing over the front of a cube).
Luckily it's not much work involved to do so:
Enable depth testing at initialization with glEnable(GL_DEPTH_TEST)
Clear depth buffer on each frame by adding it's bit to the glClear call:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
After this you should no longer see your surfaces popping on top of nearer surfaces.

Identity matrix confusion

I have the following vertex shader:
attribute vec4 Position;
attribute vec4 SourceColor;
varying vec4 DestinationColor;
uniform mat4 Projection;
void main(void) {
DestinationColor = SourceColor;
gl_Position = Projection * Position;
}
I then try to apply the following matrix to the Projection uniform:
float matrix[16] = {
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
};
glUniformMatrix4fv(projectionSlot, 1, GL_FALSE, matrix);
Shouldn't this do nothing? After running this, I can't see my objects on the screen anymore...
Yes it should be a no-op. If you remove the projection multiply then you say it works fine?
Couple ideas:
Check glGetError
Check shader compile/link status (glGetShader/Programiv)
Is the program bound during glUniform call?
Is projectionSlot a valid value?
I've never used matrices in programming, but I've taken lot's of math courses. Don't know how the Projection you're using works, but keep in mind the projection of x onto y is very different than projection of y onto x. Try switching them around if you haven't.

iOS CATransform3D Coordinates

Would really appreciate any help on this one. I have applied a 3D transformation on a view and need to identify the edge coordinates of the rendered view so I can present another view adjacent to it (without any pixels gap). Specifically I want a series of views ("pages") to fold-up like a leaflet, by animating the angle.
int dir = (isOddNumberedPage ? 1 : -1);
float angle = 10.0;
theView.frame = CGRectMake(pageNumber * 320, 0, 320, 460);
CATransform3D rotationAndPerspectiveTransform = CATransform3DIdentity;
rotationAndPerspectiveTransform.m34 = -1.0 / 2000; // Perspective
rotationAndPerspectiveTransform = CATransform3DRotate(rotationAndPerspectiveTransform,
dir * angle / (180.0 / M_PI), 0.0f, 1.0f, 0.0f);
theView.layer.transform = rotationAndPerspectiveTransform;
// Now need to get the top, left, width, height of the transformed view to correct the view's left offset
I have tried a number of ways of doing this by inspecting the CALayer, a failed attempt at using some matrix maths code snippets I found, but have not been able to crack it or even get close (depending on angle, a good 20 pixels out). Is there a way I can do this without spending 2 weeks reading a matrix maths textbook?
The frame of a view is an axis-aligned rectangle in the superview's coordinate system. The frame fully encloses the view's bounds. If the view is transformed, the frame adjusts to tightly enclose the view's new bounds.
When you apply a Y-axis rotation and perspective to a view, the left and right edges of the view move toward its anchor point (which is normally the center of the view). The left edge also grows either taller or shorter, and the right edge does the opposite.
So the frame of the view (after applying the transformation) will give you the left edge coordinate and the width of the transformed view, and the top and height of the taller edge (which might be either the left or right edge). Here's my test code:
NSLog(#"frame before tilting = %#", NSStringFromCGRect(self.tiltView.frame));
float angle = 30.0;
CATransform3D rotationAndPerspectiveTransform = CATransform3DIdentity;
rotationAndPerspectiveTransform.m34 = -1.0 / 2000; // Perspective
rotationAndPerspectiveTransform = CATransform3DRotate(rotationAndPerspectiveTransform,
1 * angle / (180.0 / M_PI), 0.0f, 1.0f, 0.0f);
self.tiltView.layer.transform = rotationAndPerspectiveTransform;
NSLog(#"frame after tilting = %#", NSStringFromCGRect(self.tiltView.frame));
Here's the output:
2012-01-04 12:44:08.405 layer[72495:f803] frame before tilting = {{50, 50}, {220, 360}}
2012-01-04 12:44:08.406 layer[72495:f803] frame after tilting = {{62.0434, 44.91}, {190.67, 370.18}}
You can also get the coordinates of the corners of the view, in the superview's coordinate space using convertPoint:fromView: or convertPoint:toView:. Test code:
CGRect bounds = self.tiltView.bounds;
CGPoint upperLeft = bounds.origin;
CGPoint upperRight = CGPointMake(CGRectGetMaxX(bounds), bounds.origin.y);
CGPoint lowerLeft = CGPointMake(bounds.origin.x, CGRectGetMaxY(bounds));
CGPoint lowerRight = CGPointMake(upperRight.x, lowerLeft.y);
#define LogPoint(P) NSLog(#"%s = %# -> %#", #P, \
NSStringFromCGPoint(P), \
NSStringFromCGPoint([self.tiltView.superview convertPoint:P fromView:self.tiltView]))
LogPoint(upperLeft);
LogPoint(upperRight);
LogPoint(lowerLeft);
LogPoint(lowerRight);
Output:
2012-01-04 13:03:00.663 layer[72635:f803] upperLeft = {0, 0} -> {62.0434, 44.91}
2012-01-04 13:03:00.663 layer[72635:f803] upperRight = {220, 0} -> {252.713, 54.8175}
2012-01-04 13:03:00.663 layer[72635:f803] lowerLeft = {0, 360} -> {62.0434, 415.09}
2012-01-04 13:03:00.663 layer[72635:f803] lowerRight = {220, 360} -> {252.713, 405.182}
Notice that the Y coordinates of the upperLeft and upperRight points are different in the superview's coordinate system.