Related
I am attempting to render a texture to a plane with OpenGL ES on an iPhone. I have worked with OpenGL before but I'm not sure why this isn't working.
When I run the code the plane is rendered as a black square and not a textured square. I believe the problem may be when loading the texture although I see no errors when I run the code.
Hopefully someone will spot a problem and be able to help. Thanks in advance.
Here is my code for the mesh.
// Mesh loading
- ( id ) init {
if ( self = [ super init ] ) {
glGenVertexArraysOES( 1, &m_vertexArray );
glBindVertexArrayOES( m_vertexArray );
glGenBuffers( 1, &m_vertexBuffer );
glBindBuffer( GL_ARRAY_BUFFER, m_vertexBuffer );
glBufferData( GL_ARRAY_BUFFER, sizeof( g_vertices ), g_vertices, GL_STATIC_DRAW );
glGenBuffers( 1, &m_texCoordBuffer );
glBindBuffer( GL_ARRAY_BUFFER, m_texCoordBuffer );
glBufferData( GL_ARRAY_BUFFER, sizeof( g_texCoords ), g_texCoords, GL_STATIC_DRAW );
}
return self;
}
- ( void ) render {
glBindBuffer( GL_ARRAY_BUFFER, m_vertexBuffer );
glVertexAttribPointer( GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 0, ( GLvoid* ) 0 );
glBindBuffer( GL_ARRAY_BUFFER, m_texCoordBuffer );
glVertexAttribPointer( GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, 0, ( GLvoid* ) 0 );
glDrawArrays( GL_TRIANGLES, 0, sizeof( g_vertices ) / sizeof( g_vertices[ 0 ] ) );
}
const GLfloat g_vertices[] = {
-1.0, -1.0, 0.0,
1.0, 1.0, 0.0,
-1.0, 1.0, 0.0,
-1.0, -1.0, 0.0,
1.0, -1.0, 0.0,
1.0, 1.0, 0.0
};
const GLfloat g_texCoords[] = {
0.0, 0.0,
1.0, 1.0,
0.0, 1.0,
0.0, 0.0,
1.0, 0.0,
1.0, 1.0
};
I only need a my vertices and tex coords right now so that is all I'm using.
Next is my texture loading.
- ( id ) init: ( NSString* ) filename {
if ( self = [ super init ] ) {
CGImageRef spriteImage = [ UIImage imageNamed: filename ].CGImage;
if ( !spriteImage ) {
NSLog( #"Failed to load image %#", filename );
exit( 1 );
}
size_t width = CGImageGetWidth( spriteImage );
size_t height = CGImageGetHeight( spriteImage );
GLubyte *spriteData = ( GLubyte* ) calloc( width * height * 4, sizeof( GLubyte ) );
CGContextRef spriteContext = CGBitmapContextCreate( spriteData, width, height, 8, 4 * width, CGImageGetColorSpace( spriteImage ), kCGImageAlphaPremultipliedLast );
CGContextDrawImage( spriteContext, CGRectMake( 0, 0, width, height ), spriteImage );
CGContextRelease( spriteContext );
glGenTextures( 1, &m_texture );
glBindTexture( GL_TEXTURE_2D, m_texture );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, ( GLuint ) width, ( GLuint ) height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData );
free( spriteData );
}
return self;
}
- ( void ) bind {
glActiveTexture( GL_TEXTURE0 );
glBindTexture( GL_TEXTURE_2D, m_texture );
}
I used the texture loading code from this tutorial.
Then here is my rendering code.
- ( void ) glkView: ( GLKView* ) view drawInRect: ( CGRect ) rect {
glClearColor( 0.65f, 0.65f, 0.65f, 1.0f );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glUseProgram( m_shaderProgram );
[ m_texture bind ];
glUniform1i( uniforms[ UNIFORM_SAMPLER ], 0 );
GLKMatrix4 mvp = GLKMatrix4Multiply( GLKMatrix4Multiply( m_projectionMatrix, m_viewMatrix ), m_modelMatrix );
glUniformMatrix4fv( uniforms[ UNIFORM_MODELVIEWPROJECTION_MATRIX ], 1, 0, mvp.m );
glEnableVertexAttribArray( GLKVertexAttribPosition );
glEnableVertexAttribArray( GLKVertexAttribTexCoord0 );
[ m_plane render ];
glDisableVertexAttribArray( GLKVertexAttribTexCoord0 );
glDisableVertexAttribArray( GLKVertexAttribPosition );
}
Vertex shader.
attribute vec3 position;
attribute vec2 texCoord;
varying lowp vec2 texCoord0;
uniform mat4 modelViewProjectionMatrix;
void main()
{
texCoord0 = texCoord;
gl_Position = modelViewProjectionMatrix * vec4( position, 1.0 );
}
And lastly fragment shader.
varying lowp vec2 texCoord0;
uniform sampler2D sampler;
void main()
{
gl_FragColor = texture2D( sampler, texCoord0.st );
}
As mentioned in the comment, you can check with a Power of Two (POT) texture. In addition, there are extensions that enable support for NonPOT (NPOT) textures like GL_IMG_texture_npot, refer to the discussion in this thread (Non power of two textures in iOS), and this thread (http://aras-p.info/blog/2012/10/17/non-power-of-two-textures/).
I'm learning OpenGL on iOS by this guide, and I want to implement everything on swift. So, there is some code were I'm getting crash:
Memory structures:
private struct Vertex {
var Position: (GLfloat, GLfloat, GLfloat)
var Color: (GLfloat, GLfloat, GLfloat, GLfloat)
}
private static var Vertices = [
Vertex(Position: (1, -1, 0) , Color: (1, 0, 0, 1)),
Vertex(Position: (1, 1, 0) , Color: (0, 1, 0, 1)),
Vertex(Position: (-1, 1, 0) , Color: (0, 0, 1, 1)),
Vertex(Position: (-1, -1, 0), Color: (0, 0, 0, 1))
]
private static var Indices: [GLubyte] = [
0, 1, 2,
2, 3, 0
]
Create vertex buffers:
var vertexBuffer = GLuint()
glGenBuffers(1, &vertexBuffer)
glBindBuffer(GLenum(GL_ARRAY_BUFFER), vertexBuffer)
glBufferData(GLenum(GL_ARRAY_BUFFER), Vertices.size, Vertices, GLenum(GL_STATIC_DRAW))
var indexBuffer = GLuint()
glGenBuffers(1, &indexBuffer)
glBindBuffer(GLenum(GL_ELEMENT_ARRAY_BUFFER), indexBuffer)
glBufferData(GLenum(GL_ELEMENT_ARRAY_BUFFER), Indices.size, Indices, GLenum(GL_STATIC_DRAW))
Setup memory offsets:
var positionPtr = 0
glVertexAttribPointer(GLuint(positionSlot), 3, GLenum(GL_FLOAT), GLboolean(GL_FALSE), GLsizei(strideofValue(Vertex)), &positionPtr)
var colorPtr = strideof(GLfloat) * 3
glVertexAttribPointer(GLuint(colorSlot), 4, GLenum(GL_FLOAT), GLboolean(GL_FALSE), GLsizei(strideofValue(Vertex)), &colorPtr)
Crash (Trying to draw):
var startPtr = 0
// EXC_BAD_ACCESS code=1 here!
glDrawElements(GLenum(GL_TRIANGLES), GLsizei(Indices.count / 3), GLenum(GL_UNSIGNED_BYTE), &startPtr)
All shaders are compiled without any errors and glClear() draws well, so I suppose my problem is concerned with VBOs.
And here how I calculate size of arrays:
extension Array
{
var size: Int {
get { return self.count * strideof(Element) }
}
}
UPD: I'm using OpenGLES 2.0.
I had learned by you guide for amount 4 months ago. I tried to convert it from objective-c to swift until draw rectangle same below picture.
Now I run it and convert to Swift 2.1. It still work and show same image below.
Here my code (Method setupVBOs, render and struct)
// Track of all our per-vertex information (currently just color and position)
struct Vertex {
var Position: (CFloat, CFloat, CFloat)
var Color: (CFloat, CFloat, CFloat, CFloat)
}
// Array with all the info for each vertex
var Vertices = [
Vertex(Position: (1, -1, 0) , Color: (1, 0, 0, 1)),
Vertex(Position: (1, 1, 0) , Color: (0, 1, 0, 1)),
Vertex(Position: (-1, 1, 0) , Color: (0, 0, 1, 1)),
Vertex(Position: (-1, -1, 0), Color: (0, 0, 0, 1))
]
// Array that gives a list of triangles to create, by specifying the 3 vertices that make up each triangle
var Indices: [GLubyte] = [
0, 1, 2,
2, 3, 0
]
//helper extensions to pass arguments to GL land
extension Array {
func size () -> Int {
return self.count * sizeofValue(self[0])
}
}
//The best way to send data to OpenGL is through something called Vertex Buffer Objects.
func setupVBOs() { // VBO : Vertex Buffer Objects.
//There are two types of vertex buffer objects – one to keep track of the per-vertex data (like we have in the Vertices array), and one to keep track of the indices that make up triangles (like we have in the Indices array).
glGenBuffers(1, &vertexBuffer)
glBindBuffer(GLenum(GL_ARRAY_BUFFER), vertexBuffer)
glBufferData(GLenum(GL_ARRAY_BUFFER), Vertices.count * sizeofValue(Vertices[0]), Vertices, GLenum(GL_STATIC_DRAW)) // send the data over to OpenGL-land.
glGenBuffers(1, &indexBuffer)
glBindBuffer(GLenum(GL_ELEMENT_ARRAY_BUFFER), indexBuffer)
glBufferData(GLenum(GL_ELEMENT_ARRAY_BUFFER), Indices.count * sizeofValue(Indices[0]), Indices, GLenum(GL_STATIC_DRAW))
}
func render() {
glClearColor(0, 104.0/255.0, 55.0/255.0, 1.0)
glClear(GLbitfield(GL_COLOR_BUFFER_BIT))
//glViewport(0, 0, GLint(frame.size.width), GLint(frame.size.height))
glViewport(0, GLint(frame.size.height/2)/2, GLint(frame.size.width), GLint(frame.size.height/2))
// feed the correct values to the two input variables for the vertex shader – the Position and SourceColor attributes.
glVertexAttribPointer(positionSlot, 3, GLenum(GL_FLOAT), GLboolean(UInt8(GL_FALSE)), GLsizei(sizeof(Vertex)), nil)
glVertexAttribPointer(colorSlot, 4, GLenum(GL_FLOAT), GLboolean(UInt8(GL_FALSE)), GLsizei(sizeof(Vertex)), UnsafePointer<Int>(bitPattern: sizeof(Float) * 3))
// This actually ends up calling your vertex shader for every vertex you pass in, and then the fragment shader on each pixel to display on the screen.
glDrawElements(GLenum(GL_TRIANGLES), GLsizei(Indices.count), GLenum(GL_UNSIGNED_BYTE), nil)
_context.presentRenderbuffer(Int(GL_RENDERBUFFER))
}
I'm working with openGL ES 2.0 and swift. I finally got to display the texture but it only one pixel is shown!
Can anyone help with this?
My simple vertex shader:
attribute vec2 TexCoordIn;
varying vec2 TexCoordOut;
void main(void) {
gl_Position = Position;
TexCoordOut = TexCoordIn;
}
And fragment shader:
varying lowp vec2 TexCoordOut;
uniform sampler2D Texture;
void main(void) {
gl_FragColor = texture2D(Texture, TexCoordOut);
}
My view controller:
// My Vertex, Vertices and Indices
struct Vertex {
var Position: (CFloat, CFloat, CFloat)
var Color: (CFloat, CFloat, CFloat, CFloat)
var TexCoord: (CFloat, CFloat)
}
var Vertices = [
Vertex(Position: (1, -1, 0) , Color: (1, 0, 0, 1), TexCoord: (1, 0)),
Vertex(Position: (1, 1, 0) , Color: (0, 1, 0, 1), TexCoord: (1, 1)),
Vertex(Position: (-1, 1, 0) , Color: (0, 0, 1, 1), TexCoord: (0, 1)),
Vertex(Position: (-1, -1, 0), Color: (0, 0, 0, 1), TexCoord: (0, 0))
]
var Indices: [GLubyte] = [
0, 1, 2,
2, 3, 0
]
func compileShaders() {
var vertexShader: GLuint = self.compileShader("Vertex", shaderType: GLenum(GL_VERTEX_SHADER))
var fragmentShader: GLuint = self.compileShader("Fragment", shaderType: GLenum(GL_FRAGMENT_SHADER))
var programHandle: GLuint = glCreateProgram()
glAttachShader(programHandle, vertexShader)
glAttachShader(programHandle, fragmentShader)
glLinkProgram(programHandle)
glUseProgram(programHandle)
glEnableVertexAttribArray(self.positionSlot)
glEnableVertexAttribArray(self.colorSlot)
texCoordSlot = GLuint(glGetAttribLocation(programHandle, "TexCoordIn"))
glEnableVertexAttribArray(texCoordSlot)
let pointer = UnsafePointer<Int>(bitPattern: sizeof(Float) * 7)
glVertexAttribPointer(texCoordSlot, 2, GLenum(GL_FLOAT), GLboolean(UInt8(GL_FALSE)), GLsizei(sizeof(Vertex)), pointer)
textureUniform = GLuint(glGetUniformLocation(programHandle, "Texture"))
}
func setupVBOs() {
glGenVertexArraysOES(1, &VAO);
glBindVertexArrayOES(VAO);
glGenBuffers(1, &vertexBuffer)
glBindBuffer(GLenum(GL_ARRAY_BUFFER), vertexBuffer)
glBufferData(GLenum(GL_ARRAY_BUFFER), Vertices.size(), Vertices, GLenum(GL_STATIC_DRAW))
glEnableVertexAttribArray(positionSlot)
glVertexAttribPointer(positionSlot, 3, GLenum(GL_FLOAT), GLboolean(UInt8(GL_FALSE)), GLsizei(sizeof(Vertex)), nil)
glGenBuffers(1, &indexBuffer)
glBindBuffer(GLenum(GL_ELEMENT_ARRAY_BUFFER), indexBuffer)
glBufferData(GLenum(GL_ELEMENT_ARRAY_BUFFER), Indices.size(), Indices, GLenum(GL_STATIC_DRAW))
glBindBuffer(GLenum(GL_ARRAY_BUFFER), 0)
glBindVertexArrayOES(0)
}
func render() {
glBindVertexArrayOES(VAO);
glActiveTexture(GLenum(GL_TEXTURE0))
glBindTexture(GLenum(GL_TEXTURE_2D), floorTexture)
glUniform1i(GLint(textureUniform), GLint(0))
glDrawElements(GLenum(GL_TRIANGLES), GLsizei(Indices.count), GLenum(GL_UNSIGNED_BYTE), nil)
glContext!.presentRenderbuffer(Int(GL_RENDERBUFFER))
glBindVertexArrayOES(0)
}
The foundation I learned in the great Ray Wenderlich Tutorial. But I could not make it to work in swift.
I have an object and I can render it but I want to use its vertices twice but I don't know how to.
Edit: I wan them to translate independently during the game.
this is my code reading object from txt:
fin.open("piyon.txt");
fin >> vertexCountpiyon;
verticespiyon = new SimpleVertex[vertexCountpiyon];
for(int i=0; i<vertexCountpiyon; i++)
{
fin >> verticespiyon[i].Pos.x >> verticespiyon[i].Pos.y >> verticespiyon[i].Pos.z;
fin >> verticespiyon[i].Tex.x >> verticespiyon[i].Tex.y;
fin >> verticespiyon[i].Normal.x >> verticespiyon[i].Normal.y >> verticespiyon[i].Normal.z;
}
fin.close();
bd.ByteWidth = sizeof( SimpleVertex ) * vertexCountpiyon;
ZeroMemory( &InitData, sizeof(InitData) );
InitData.pSysMem = verticespiyon;
hr = g_pd3dDevice->CreateBuffer( &bd, &InitData, &g_pVertexBuffer_piyon );
if( FAILED( hr ) ) return hr;
and my render code:
g_pImmediateContext->IASetVertexBuffers( 0, 1, &g_pVertexBuffer_piyon, &stride, &offset );
cBuffer.vMeshColor = XMFLOAT4( 1.0f, 1.0f, 1.0f, 1.0f );
XMMATRIX mTranslateBeyazPiyon = XMMatrixTranslation( -17.5F, 0, -12.5F );
cBuffer.mWorld = XMMatrixTranspose( mTranslateBeyazPiyon );
g_World_Piyon = mTranslateBeyazPiyon;
g_pImmediateContext->UpdateSubresource( g_pConstantBuffer, 0, NULL, &cBuffer, 0, 0 );
g_pImmediateContext->VSSetShader( g_pVertexShader, NULL, 0 );
g_pImmediateContext->VSSetConstantBuffers( 2, 1, &g_pConstantBuffer );
g_pImmediateContext->PSSetShader( g_pPixelShader, NULL, 0 );
g_pImmediateContext->PSSetConstantBuffers( 2, 1, &g_pConstantBuffer );
g_pImmediateContext->Draw( 7050, 0 );
If you want to just draw the same object in a different place, you only need to change your world matrix and then draw again. So, using parts of your code for reference, something like this:
// set world matrix for first object ...
XMMATRIX mTranslateBeyazPiyon = XMMatrixTranslation( -17.5F, 0, -12.5F );
cBuffer.mWorld = XMMatrixTranspose( mTranslateBeyazPiyon );
g_pImmediateContext->UpdateSubresource( g_pConstantBuffer, 0, NULL, &cBuffer, 0, 0 );
// ... set any other common state
// draw first object
g_pImmediateContext->Draw( 7050, 0 );
// set world matrix for second object ... for example, translated somewhere else
mTranslateBeyazPiyon = XMMatrixTranslation( -34.5F, 0, -24.5F );
cBuffer.mWorld = XMMatrixTranspose( mTranslateBeyazPiyon );
g_pImmediateContext->UpdateSubresource( g_pConstantBuffer, 0, NULL, &cBuffer, 0, 0 );
// draw second object
g_pImmediateContext->Draw( 7050, 0 );
I have two different images (Image A and Image B), whose histograms (histImage and histImage1) i have already computed.
Now I want that the histogram of Image A becomes the histogram of Image B. So that the Image B gets the colors similar to Image A.
code is as follow:
#include "stdafx.h"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
using namespace std;
using namespace cv;
int main( )
{
Mat src, dst, src1;
/// Load image
src = imread("ImageA", 1 ); // Image A
src1 = imread("ImageB", 1 ); // Image B
if( !src.data )
{ return -1; }
/// Separate the image in 3 places ( B, G and R )
vector<Mat> bgr_planes;
vector<Mat> bgr_planes1;
split( src, bgr_planes );
split( src1, bgr_planes1 );
/// Establish the number of bins
int histSize = 256;
/// Set the ranges ( for B,G,R) )
float range[] = { 0, 256 } ;
const float* histRange = { range };
bool uniform = true; bool accumulate = false;
Mat b_hist, g_hist, r_hist; //ImageA
Mat b_hist1, g_hist1, r_hist1; //ImageB
/// Compute the histograms of Image A
calcHist( &bgr_planes[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRange, uniform, accumulate );
calcHist( &bgr_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRange, uniform, accumulate );
calcHist( &bgr_planes[2], 1, 0, Mat(), r_hist, 1, &histSize, &histRange, uniform, accumulate );
/// Compute the histograms of Image B
calcHist( &bgr_planes1[0], 1, 0, Mat(), b_hist1, 1, &histSize, &histRange, uniform, accumulate );
calcHist( &bgr_planes1[1], 1, 0, Mat(), g_hist1, 1, &histSize, &histRange, uniform, accumulate );
calcHist( &bgr_planes1[2], 1, 0, Mat(), r_hist1, 1, &histSize, &histRange, uniform, accumulate );
// Draw the histograms for B, G and R
int hist_w = 512; int hist_h = 400; //Image A
int bin_w = cvRound( (double) hist_w/histSize ); //Image A
int hist_w1 = 512; int hist_h1 = 400; //Image B
int bin_w1 = cvRound( (double) hist_w1/histSize );//Image B
Mat histImage( hist_h, hist_w, CV_8UC3, Scalar( 0,0,0) ); //ImageA
Mat histImage1( hist_h1, hist_w1, CV_8UC3, Scalar( 0,0,0) ); //ImageB
/// Normalize the result to [ 0, histImage.rows ] ImageA
normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
/// Normalize the result to [ 0, histImage.rows ] ImageB
normalize(b_hist1, b_hist1, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
normalize(g_hist1, g_hist1, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
normalize(r_hist1, r_hist1, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
/// Draw for each channel ImageA
for( int i = 1; i < histSize; i++ )
{
line( histImage, Point( bin_w*(i-1), hist_h - cvRound(b_hist.at<float>(i-1)) ) ,
Point( bin_w*(i), hist_h - cvRound(b_hist.at<float>(i)) ),
Scalar( 255, 0, 0), 2, 8, 0 );
line( histImage, Point( bin_w*(i-1), hist_h - cvRound(g_hist.at<float>(i-1)) ) ,
Point( bin_w*(i), hist_h - cvRound(g_hist.at<float>(i)) ),
Scalar( 0, 255, 0), 2, 8, 0 );
line( histImage, Point( bin_w*(i-1), hist_h - cvRound(r_hist.at<float>(i-1)) ) ,
Point( bin_w*(i), hist_h - cvRound(r_hist.at<float>(i)) ),
Scalar( 0, 0, 255), 2, 8, 0 );
}
////////////////////////////////////////////////////
/// Draw for each channel ImageB
for( int i = 1; i < histSize; i++ )
{
line( histImage1, Point( bin_w1*(i-1), hist_h1 - cvRound(b_hist1.at<float>(i-1)) ) ,
Point( bin_w1*(i), hist_h1 - cvRound(b_hist1.at<float>(i)) ),
Scalar( 255, 0, 0), 2, 8, 0 );
line( histImage1, Point( bin_w1*(i-1), hist_h1 - cvRound(g_hist1.at<float>(i-1)) ) ,
Point( bin_w1*(i), hist_h1 - cvRound(g_hist1.at<float>(i)) ),
Scalar( 0, 255, 0), 2, 8, 0 );
line( histImage1, Point( bin_w1*(i-1), hist_h1 - cvRound(r_hist1.at<float>(i-1)) ) ,
Point( bin_w1*(i), hist_h1 - cvRound(r_hist1.at<float>(i)) ),
Scalar( 0, 0, 255), 2, 8, 0 );
}
/////////////////////////////////////////////////////
/// Display
namedWindow("calcHist", CV_WINDOW_AUTOSIZE );
imshow("face ", histImage ); //Histogram of Image A
/// Display
namedWindow("calcHist1", CV_WINDOW_AUTOSIZE );
imshow("body ", histImage1 ); //Histogram of Image B
waitKey(0);
return 0;
}
One way to swap the histograms would be to follow the methodology used in histogram equalisation.
Compute the histograms (H1 and H2) respectively for the two images (I1 and I2) and normalise them (already done in your code).
Compute the cumulative histograms - also called cumulative distribution functions - C1 and C2 corresponding to H1 and H2 as explained here.
Substitute new values for every pixel in I1 using the cumulative histogram C2 as explained here.
Do the same for every pixel in I2, using cumulative histogram C1.