Related
I'm loading an image to the screen using DirectX11, but the image becomes more saturated. Left is the loaded image and right is the original image.
Strange thing is that this happens only when I'm loading large images. The resolution of the image I'm trying to print is 1080 x 675 and my window size is 1280 x 800. Also, although the original image has a high resolution the image becomes a little pixelated. This is solved if I use LINEAR filter but I'm curious why this is happening. I'm fairly new to DirectX and I'm struggling..
Vertex data:
_vertices[0].p = { -1.0f, 1.0f, 0.0f };
//_vertices[0].c = { 1.0f, 1.0f, 1.0f, 1.0f };
_vertices[0].t = { 0.0f, 0.0f };
_vertices[1].p = { 1.0f, 1.0f, 0.0f };
//_vertices[1].c = { 1.0f, 1.0f, 1.0f, 1.0f };
_vertices[1].t = { 1.0f, 0.0f };
_vertices[2].p = { -1.0f, -1.0f, 0.0f };
//_vertices[2].c = { 1.0f, 1.0f, 1.0f, 1.0f };
_vertices[2].t = { 0.0f, 1.0f };
_vertices[3].p = { 1.0f, -1.0f, 0.0f };
//_vertices[3].c = { 1.0f, 1.0f, 1.0f, 1.0f };
_vertices[3].t = { 1.0f, 1.0f };
Vertex layout:
D3D11_INPUT_ELEMENT_DESC elementDesc[] = {
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
//{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0},
{ "TEXTURE", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 28, D3D11_INPUT_PER_VERTEX_DATA, 0},
};
Sampler state:
D3D11_SAMPLER_DESC samplerDesc;
ZeroMemory(&samplerDesc, sizeof(samplerDesc));
samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
device->CreateSamplerState(&samplerDesc, &g_defaultSS);
Vertex shader:
struct VS_IN
{
float3 p : POSITION;
//float4 c : COLOR;
float2 t : TEXTURE;
};
struct VS_OUT
{
float4 p : SV_POSITION;
//float4 c : COLOR0;
float2 t : TEXCOORD0;
};
VS_OUT VSMain(VS_IN input)
{
VS_OUT output = (VS_OUT)0;
output.p = float4(input.p, 1.0f);
//output.c = input.c;
output.t = input.t;
return output;
}
Pixel shader:
Texture2D g_texture : register(t0);
SamplerState g_sampleWrap : register(s0);
float4 PSMain(VS_OUT input) : SV_Target
{
float4 vColor = g_texture.Sample(g_sampleWrap, input.t);
return vColor; //* input.c;
}
This is most likely an issue of colorspace. If rendering using 'linear colors' (which is recommended), then likely your image is in sRGB colorspace. You can let the texture hardware deal with the gamma by using DXGI_FORMAT_*_SRGB formats for your texture, or you can do it directly in the shader.
See these resources:
Linear-Space Lighting (i.e. Gamma)
Chapter 24. The Importance of Being Linear, GPU Gems 3
Gamma-correct rendering
In the DirectX Tool Kit, you can do various load-time tricks as well. See DDSTextureLoader and WICTextureLoader.
I am trying to render large images (10K x 10K) inside a CView in MFC. The performance with GdiPlus is really slow (0.5 fps to be precise). Is there any free or commercial library which I could use for the purpose?
DirectX Rendering Code
float halfWidth = m_CurWidth/2.0;
float halfHeight = m_CurHeight/2.0;
D3DXMATRIX P;
D3DXMatrixOrthoLH(&P, (float)rect.Width(), (float)rect.Height(), -10, 10);
m_pDevice3D->SetTransform(D3DTS_PROJECTION, &P);
float cornerX = m_Left;
float cornerY = -m_Top;
VERTEX g_vVertices[4];
{
g_vVertices[0] = VERTEX(cornerX + (-1.0f * halfWidth), cornerY + (1.0f * halfHeight), 0.0f, 0.0f, 0.0f );
g_vVertices[1] = VERTEX(cornerX + (1.0f * halfWidth), cornerY + (1.0f * halfHeight), 0.0f, 1.0f, 0.0f );
g_vVertices[2] = VERTEX(cornerX + (-1.0f * halfWidth), cornerY + (-1.0f * halfHeight), 0.0f, 0.0f, 1.0f );
g_vVertices[3] = VERTEX(cornerX + (1.0f * halfWidth), cornerY + (-1.0f * halfHeight), 0.0f, 1.0f, 1.0f );
};
void * pVertices;
m_pVB->Lock( 0, sizeof(pVertices), (void**)&pVertices, 0 );
memcpy( pVertices, g_vVertices, sizeof(g_vVertices));
m_pVB->Unlock();
if(m_pDevice3D){
m_pDevice3D->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
0xffffffff, 1.0f, 0);
m_pDevice3D->BeginScene();
m_pDevice3D->SetFVF(D3DFVF_VERTEX);
m_pDevice3D->SetStreamSource(0, m_pVB, 0, sizeof(VERTEX));
// Draw primitives using presently enabled texture.
m_pDevice3D->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
m_pDevice3D->EndScene();
m_pDevice3D->Present(0, 0, 0, 0);
}
i took the code from the OpenGL ES 2.0 Tutorial from : github.com/learnopengles/Learn-OpenGLES-Tutorials
and customized the class "LessonOneRenderer" to test a barrel distortin Shader like mentioned on this site:
www.geeks3d.com/20140213/glsl-shader-library-fish-eye-and-dome-and-barrel-distortion-post-processing-filters/2/
This is the "untouched" Result without calling the distort() function:
http://fs1.directupload.net/images/150125/hw746rcn.png
and the result calling the function :
http://fs2.directupload.net/images/150125/f84arxoj.png
/**
* This class implements our custom renderer. Note that the GL10 parameter passed in is unused for OpenGL ES 2.0
* renderers -- the static class GLES20 is used instead.
*/
public class LessonOneRenderer implements GLSurfaceView.Renderer
{
/**
* Store the model matrix. This matrix is used to move models from object space (where each model can be thought
* of being located at the center of the universe) to world space.
*/
private float[] mModelMatrix = new float[16];
/**
* Store the view matrix. This can be thought of as our camera. This matrix transforms world space to eye space;
* it positions things relative to our eye.
*/
private float[] mViewMatrix = new float[16];
/** Store the projection matrix. This is used to project the scene onto a 2D viewport. */
private float[] mProjectionMatrix = new float[16];
/** Allocate storage for the final combined matrix. This will be passed into the shader program. */
private float[] mMVPMatrix = new float[16];
/** Store our model data in a float buffer. */
private final FloatBuffer mTriangle1Vertices;
/** This will be used to pass in the transformation matrix. */
private int mMVPMatrixHandle;
/** This will be used to pass in model position information. */
private int mPositionHandle;
/** This will be used to pass in model color information. */
private int mColorHandle;
/** How many bytes per float. */
private final int mBytesPerFloat = 4;
/** How many elements per vertex. */
private final int mStrideBytes = 7 * mBytesPerFloat;
/** Offset of the position data. */
private final int mPositionOffset = 0;
/** Size of the position data in elements. */
private final int mPositionDataSize = 3;
/** Offset of the color data. */
private final int mColorOffset = 3;
/** Size of the color data in elements. */
private final int mColorDataSize = 4;
private FloatBuffer vertexBuffer;
private ShortBuffer drawListBuffer;
// number of coordinates per vertex in this array
static final int COORDS_PER_VERTEX = 3;
// X Y Z
static float squareCoords[] = { -0.5f, 0.5f, 0.0f, // top left
-0.5f, -0.5f, 0.0f, // bottom left
0.5f, -0.5f, 0.0f, // bottom right
0.5f, 0.5f, 0.0f }; // top right
private short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // order to draw vertices
float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 1.0f };
static final int vertexStride = COORDS_PER_VERTEX * 4;
static final int vertexCount = 4;
private ByteBuffer dlb;
/**
* Initialize the model data.
*/
public LessonOneRenderer()
{
ByteBuffer bb = ByteBuffer.allocateDirect(squareCoords.length * 4); // (# of coordinate values * 4 bytes per float)
bb.order(ByteOrder.nativeOrder());
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(squareCoords);
vertexBuffer.position(0);
// initialize byte buffer for the draw list
ByteBuffer dlb = ByteBuffer.allocateDirect(drawOrder.length * 2); // (# of coordinate values * 2 bytes per short)
dlb.order(ByteOrder.nativeOrder());
drawListBuffer = dlb.asShortBuffer();
drawListBuffer.put(drawOrder);
drawListBuffer.position(0);
// Define points for equilateral triangles.
// This triangle is red, green, and blue.
final float[] triangle1VerticesData = {
// X, Y, Z,
// R, G, B, A
-0.5f, 0.5f, 0.0f, // top left
1.0f, 0.0f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.0f,// bottom left
0.0f, 0.0f, 1.0f, 1.0f,
0.5f, -0.5f, 0.0f, // bottom right
0.0f, 1.0f, 0.0f, 1.0f
,
0.5f, 0.5f, 0.0f, // top right
0.0f, 1.0f, 0.0f, 1.0f
};
// Initialize the buffers.
mTriangle1Vertices = ByteBuffer.allocateDirect(triangle1VerticesData.length * mBytesPerFloat)
.order(ByteOrder.nativeOrder()).asFloatBuffer();
mTriangle1Vertices.put(triangle1VerticesData).position(0);
// initialize byte buffer for the draw list
dlb = ByteBuffer.allocateDirect(drawOrder.length * 2); // (# of coordinate values * 2 bytes per short)
dlb.order(ByteOrder.nativeOrder());
drawListBuffer = dlb.asShortBuffer();
drawListBuffer.put(drawOrder);
drawListBuffer.position(0);
}
#Override
public void onSurfaceCreated(GL10 glUnused, EGLConfig config)
{
// Set the background clear color to gray.
GLES20.glClearColor(0.5f, 0.5f, 0.5f, 0.5f);
// Position the eye behind the origin.
final float eyeX = 0.0f;
final float eyeY = 0.0f;
final float eyeZ = 1.5f;
// We are looking toward the distance
final float lookX = 0.0f;
final float lookY = 0.0f;
final float lookZ = -5.0f;
// Set our up vector. This is where our head would be pointing were we holding the camera.
final float upX = 0.0f;
final float upY = 1.0f;
final float upZ = 0.0f;
// Set the view matrix. This matrix can be said to represent the camera position.
// NOTE: In OpenGL 1, a ModelView matrix is used, which is a combination of a model and
// view matrix. In OpenGL 2, we can keep track of these matrices separately if we choose.
Matrix.setLookAtM(mViewMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY, lookZ, upX, upY, upZ);
final String vertexShader =
"uniform mat4 u_MVPMatrix; \n" // A constant representing the combined model/view/projection matrix.
+ "attribute vec4 a_Position; \n" // Per-vertex position information we will pass in.
+ "attribute vec4 a_Color; \n" // Per-vertex color information we will pass in.
+ "varying vec4 a_Pos; \n"
+ "varying vec4 v_Color; \n" // This will be passed into the fragment shader.
+" "
+"vec4 Distort(vec4 p){ \n"
+" float BarrelPower = 0.4; \n"
+" vec2 v = p.xy / p.w; \n"
+" float radius = length(v); \n"
+" if (radius > 0.0){ \n"
+" float theta = atan(v.y,v.x); \n"
+" radius = pow(radius, BarrelPower);\n"
+" v.x = radius * cos(theta); \n"
+" v.y = radius * sin(theta); \n"
+" p.xy = v.xy * p.w; \n"
+" }"
+" \n"
+" return p; \n"
+" } \n"
+ "void main() \n" // The entry point for our vertex shader.
+ "{ \n"
+ " v_Color = a_Color; \n" // Pass the color through to the fragment shader.
+ " vec4 P = u_MVPMatrix * a_Position;" // It will be interpolated across the triangle.
+ " gl_Position = Distort(P); \n" // gl_Position is a special variable used to store the final position.
+ " \n" // Multiply the vertex by the matrix to get the final point in
+ "} \n"; // normalized screen coordinates.
final String fragmentShader =
// Set the default precision to medium. We don't need as high of a
"varying vec4 a_Pos;" // precision in the fragment shader.
+ "varying vec4 v_Color; \n" // This is the color from the vertex shader interpolated across the
// triangle per fragment.
+ "void main() \n" // The entry point for our fragment shader.
+ "{ vec4 c = vec4(1.0); \n"
+ " gl_FragColor = v_Color; \n" // Pass the color directly through the pipeline.
+ "} \n";
// Load in the vertex shader.
int vertexShaderHandle = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
if (vertexShaderHandle != 0)
{
// Pass in the shader source.
GLES20.glShaderSource(vertexShaderHandle, vertexShader);
// Compile the shader.
GLES20.glCompileShader(vertexShaderHandle);
// Get the compilation status.
final int[] compileStatus = new int[1];
GLES20.glGetShaderiv(vertexShaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
// If the compilation failed, delete the shader.
if (compileStatus[0] == 0)
{
GLES20.glDeleteShader(vertexShaderHandle);
vertexShaderHandle = 0;
}
}
if (vertexShaderHandle == 0)
{
throw new RuntimeException("Error creating vertex shader.");
}
// Load in the fragment shader shader.
int fragmentShaderHandle = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
if (fragmentShaderHandle != 0)
{
// Pass in the shader source.
GLES20.glShaderSource(fragmentShaderHandle, fragmentShader);
// Compile the shader.
GLES20.glCompileShader(fragmentShaderHandle);
// Get the compilation status.
final int[] compileStatus = new int[1];
GLES20.glGetShaderiv(fragmentShaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
// If the compilation failed, delete the shader.
if (compileStatus[0] == 0)
{
GLES20.glDeleteShader(fragmentShaderHandle);
fragmentShaderHandle = 0;
}
}
if (fragmentShaderHandle == 0)
{
throw new RuntimeException("Error creating fragment shader.");
}
// Create a program object and store the handle to it.
int programHandle = GLES20.glCreateProgram();
if (programHandle != 0)
{
// Bind the vertex shader to the program.
GLES20.glAttachShader(programHandle, vertexShaderHandle);
// Bind the fragment shader to the program.
GLES20.glAttachShader(programHandle, fragmentShaderHandle);
// Bind attributes
GLES20.glBindAttribLocation(programHandle, 0, "a_Position");
GLES20.glBindAttribLocation(programHandle, 1, "a_Color");
// Link the two shaders together into a program.
GLES20.glLinkProgram(programHandle);
// Get the link status.
final int[] linkStatus = new int[1];
GLES20.glGetProgramiv(programHandle, GLES20.GL_LINK_STATUS, linkStatus, 0);
// If the link failed, delete the program.
if (linkStatus[0] == 0)
{
GLES20.glDeleteProgram(programHandle);
programHandle = 0;
}
}
if (programHandle == 0)
{
throw new RuntimeException("Error creating program.");
}
// Set program handles. These will later be used to pass in values to the program.
mMVPMatrixHandle = GLES20.glGetUniformLocation(programHandle, "u_MVPMatrix");
mPositionHandle = GLES20.glGetAttribLocation(programHandle, "a_Position");
mColorHandle = GLES20.glGetAttribLocation(programHandle, "a_Color");
// Tell OpenGL to use this program when rendering.
GLES20.glUseProgram(programHandle);
}
#Override
public void onSurfaceChanged(GL10 glUnused, int width, int height)
{
// Set the OpenGL viewport to the same size as the surface.
GLES20.glViewport(0, 0, width, height);
// Create a new perspective projection matrix. The height will stay the same
// while the width will vary as per aspect ratio.
final float ratio = (float) width / height;
final float left = -ratio;
final float right = ratio;
final float bottom = -1.0f;
final float top = 1.0f;
final float near = 1.0f;
final float far = 10.0f;
Matrix.frustumM(mProjectionMatrix, 0, left, right, bottom, top, near, far);
}
#Override
public void onDrawFrame(GL10 glUnused)
{
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
// Do a complete rotation every 10 seconds.
long time = SystemClock.uptimeMillis() % 10000L;
float angleInDegrees = (360.0f / 10000.0f) * ((int) time);
// Draw the triangle facing straight on.
//Matrix.setIdentityM(mModelMatrix, 0);
//Matrix.rotateM(mModelMatrix, 0, angleInDegrees, 0.0f, 0.0f, 1.0f);
//drawTriangle(mTriangle1Vertices);
//Draw Square
Matrix.setIdentityM(mModelMatrix, 0);
Matrix.translateM(mModelMatrix, 0, 0.0f, -0.7f, 0.0f);
//Matrix.rotateM(mModelMatrix, 0, angleInDegrees, 0.0f, 0.0f, 1.0f);
this.drawSquare(mTriangle1Vertices);
//Draw Square
Matrix.setIdentityM(mModelMatrix, 0);
Matrix.translateM(mModelMatrix, 0, 0.0f, 0.7f, 0.0f);
//Matrix.rotateM(mModelMatrix, 0, angleInDegrees, 0.0f, 0.0f, 1.0f);
this.drawSquare(mTriangle1Vertices);
// Draw one translated a bit down and rotated to be flat on the ground.
//Matrix.setIdentityM(mModelMatrix, 0);
//Matrix.translateM(mModelMatrix, 0, 0.0f, -1.0f, 0.0f);
//Matrix.rotateM(mModelMatrix, 0, 90.0f, 1.0f, 0.0f, 0.0f);
//Matrix.rotateM(mModelMatrix, 0, angleInDegrees, 0.0f, 0.0f, 1.0f);
//drawTriangle(mTriangle2Vertices);
// Draw one translated a bit to the right and rotated to be facing to the left.
//Matrix.setIdentityM(mModelMatrix, 0);
//Matrix.translateM(mModelMatrix, 0, 1.0f, 0.0f, 0.0f);
//Matrix.rotateM(mModelMatrix, 0, 90.0f, 0.0f, 1.0f, 0.0f);
//Matrix.rotateM(mModelMatrix, 0, angleInDegrees, 0.0f, 0.0f, 1.0f);
//drawTriangle(mTriangle3Vertices);
// test.draw();
}
/**
* Draws a triangle from the given vertex data.
*
* #param aTriangleBuffer The buffer containing the vertex data.
*/
private void drawTriangle(final FloatBuffer aTriangleBuffer)
{
// Pass in the position information
aTriangleBuffer.position(mPositionOffset);
GLES20.glVertexAttribPointer(mPositionHandle, mPositionDataSize, GLES20.GL_FLOAT, false,
mStrideBytes, aTriangleBuffer);
GLES20.glEnableVertexAttribArray(mPositionHandle);
// Pass in the color information
aTriangleBuffer.position(mColorOffset);
GLES20.glVertexAttribPointer(mColorHandle, mColorDataSize, GLES20.GL_FLOAT, false,
mStrideBytes, aTriangleBuffer);
GLES20.glEnableVertexAttribArray(mColorHandle);
// This multiplies the view matrix by the model matrix, and stores the result in the MVP matrix
// (which currently contains model * view).
Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0);
// This multiplies the modelview matrix by the projection matrix, and stores the result in the MVP matrix
// (which now contains model * view * projection).
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0);
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);
}
private void drawSquare(final FloatBuffer aTriangleBuffer)
{
// Pass in the position information
aTriangleBuffer.position(mPositionOffset);
GLES20.glVertexAttribPointer(mPositionHandle, mPositionDataSize, GLES20.GL_FLOAT, false,
mStrideBytes, aTriangleBuffer);
GLES20.glEnableVertexAttribArray(mPositionHandle);
// Pass in the color information
aTriangleBuffer.position(mColorOffset);
GLES20.glVertexAttribPointer(mColorHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false,
vertexStride, aTriangleBuffer);
GLES20.glEnableVertexAttribArray(mColorHandle);
// This multiplies the view matrix by the model matrix, and stores the result in the MVP matrix
// (which currently contains model * view).
Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0);
// This multiplies the modelview matrix by the projection matrix, and stores the result in the MVP matrix
// (which now contains model * view * projection).
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0);
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 4);
}
}
Does anybody have an idea what i'm missing to distort the squares like in the example?
You apply the distortion effect in the vertex shader. So all you are doing is moving the 4 corners of those spheres. You can't achieve the desired effect that way.
Threre are different options. You theoretically could use some higher tesselation for your squares, so you just create a 2D grid of vertices, which then can indivudually be moved according to the distortion. If your grid is fine enough, the piecewise-linear nature of that approximation will not be visible anymore.
However, such effects are typically done differently. One usually does not tune the geometric models for specific effects. That kind of distortions usually are applied in screen-space, as a post-processing effect (and the link you posted does exactly this). The idea is that you can render the whole scene into a texture, and draw a single tetxured rectangle filling the whole screen as the final pass. In that pass, you can apply the distortion to the texture coordinates in the fragment shader, just as in the original example.
All of that can be done in OpenGL ES, too. The keywords to look for are RTT (render to texture) and FBOs (framebuffer objects). On GLES, this feature is available as the OES_framebuffer_object extension (which is widely supported on most ES implementations).
However, using that stuff is definitively a bit more advanced than your typical "lessson 1" of some tutorial, you might want to read some other lessons first before trying that... ;)
I'm trying to rotate a triangle around the the Y axis. When I rotate it about the Z axis, everything is fine. But when I try rotating about the Y axis, all I get is a half triangle, rotating about the Y axis. I'm using PowerVRs OpenGL ES 2.0 SDK. My Init and Draw functions are below.
int Init(ESContext* esContext)
{
UserData* userData = (UserData *)esContext->userData;
const char *vShaderStr =
"attribute vec4 vPosition; \n"
"uniform mat4 MVPMatrix;"
"void main() \n"
"{ \n"
" gl_Position = MVPMatrix * vPosition;\n"
"} \n";
const char *fShaderStr =
"precision mediump float; \n"
"void main() \n"
"{ \n"
" gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); \n"
"} \n";
GLuint vertexShader;
GLuint fragmentShader;
GLuint programObject;
GLint linked;
GLfloat ratio = 320.0f/240.0f;
vertexShader = LoadShader(GL_VERTEX_SHADER, vShaderStr);
fragmentShader = LoadShader(GL_FRAGMENT_SHADER, fShaderStr);
programObject = glCreateProgram();
if (programObject == 0)
return 0;
glAttachShader(programObject, vertexShader);
glAttachShader(programObject, fragmentShader);
glBindAttribLocation(programObject, 0, "vPosition");
glLinkProgram(programObject);
glGetProgramiv(programObject, GL_INFO_LOG_LENGTH, &linked);
if (!linked)
{
GLint infoLen = 0;
glGetProgramiv(programObject, GL_INFO_LOG_LENGTH, &infoLen);
if (infoLen > 1)
{
char* infoLog = (char *)malloc(sizeof(char) * infoLen);
glGetProgramInfoLog(programObject, infoLen, NULL, infoLog);
free(infoLog);
}
glDeleteProgram(programObject);
return FALSE;
}
userData->programObject = programObject;
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glViewport(0, 0, esContext->width, esContext->height);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(userData->programObject);
userData->angle = 0.0f;
userData->start = time(NULL);
userData->ProjMatrix = PVRTMat4::Perspective(ratio*2.0f, 2.0f, 3.0f, 7.0f, PVRTMat4::eClipspace::OGL, false, false);
userData->ViewMatrix = PVRTMat4::LookAtLH(PVRTVec3(0.0f, 0.0f, -3.0f), PVRTVec3(0.0f, 0.0f, 0.0f), PVRTVec3(0.0f, 1.0f, 0.0f));
return TRUE;
}
void Draw(ESContext *esContext)
{
GLfloat vVertices[] = {0.0f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f};
GLint MVPHandle;
double timelapse;
PVRTMat4 MVPMatrix = PVRTMat4::Identity();
UserData* userData = (UserData *)esContext->userData;
timelapse = difftime(time(NULL), userData->start) * 1000;
if(timelapse > 16.0f) //Maintain approx 60FPS
{
if (userData->angle > 360.0f)
{
userData->angle = 0.0f;
}
else
{
userData->angle += 0.1f;
}
}
userData->ModelMatrix = PVRTMat4::RotationY(userData->angle);
MVPMatrix = userData->ViewMatrix * userData->ModelMatrix;
MVPMatrix = userData->ProjMatrix * MVPMatrix;
MVPHandle = glGetUniformLocation(userData->programObject, "MVPMatrix");
glUniformMatrix4fv(MVPHandle, 1, FALSE, MVPMatrix.ptr());
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vVertices);
glEnableVertexAttribArray(0);
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_TRIANGLES, 0, 3);
eglSwapBuffers(esContext->eglDisplay, esContext->eglSurface);
}
PVRTMat4::Perspective(ratio*2.0f, 2.0f, 3.0f, 7.0f, PVRTMat4::eClipspace::OGL, false, false); puts the near clipping plane at 3.0f units away from the camera (via the third argument).
PVRTMat4::LookAtLH(PVRTVec3(0.0f, 0.0f, -3.0f), PVRTVec3(0.0f, 0.0f, 0.0f), PVRTVec3(0.0f, 1.0f, 0.0f)); places the camera at (0, 0, -3), looking back at (0, 0, 0).
You generate a model matrix directly using PVRTMat4::RotationY(userData->angle); so that matrix does no translation. The triangle you're drawing remains positioned on (0, 0, 0) as per its geometry.
So what's happening is that the parts of the triangle that get closer to the camera than 3 units are being clipped by the near clipping plane. The purpose of the near clipping plane is effectively to place the lens of the camera relative to where the image will be perceived. Or it's like specifying the distance from user to screen, if you prefer.
You therefore want either to bring the near clip plane closer to the camera or to move the camera further away from the triangle.
I have a curious problem about an App which MainView is inherited from NSOpenGlView.
I am able to draw many things in it, like a basic OpenGL tutorial.... but when I try to implement a basic trackball, it looks like the app waits until I release the mouse button before it refreshes my view... even if I call directly the "DrawRect" callback from the "MouseDragged" callback, it acts the same. Then, I really can't find out how to do such a basic thing and what is the problem about my solution..
Any idea?
My NSOpenGLVIew has double buffer, and and additional depth buffer.
Here are the main messages.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (void)mouseDragged:(NSEvent *)theEvent {
//[[self openGLContext] makeCurrentContext];
float curPos[3], dx, dy, dz;
dx = curPos[0] - lastPos[0];
dy = curPos[1] - lastPos[1];
dz = curPos[2] - lastPos[2];
angle = 90.0 * sqrt(dx*dx + dy*dy + dz*dz);
axis[0] = lastPos[1]*curPos[2] - lastPos[2]*curPos[1];
axis[1] = lastPos[2]*curPos[0] - lastPos[0]*curPos[2];
axis[2] = lastPos[0]*curPos[1] - lastPos[1]*curPos[0];
//glutPostRedisplay();
//[self drawRect:self.bounds]; // different attempts
[self setNeedsDisplay:YES]; //
//[self display];
}
#pragma mark Mouse Handling
- (void)mouseDown:(NSEvent *)theEvent {
m_PreviousMouseLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil];
ptov(m_PreviousMouseLoc.x,m_PreviousMouseLoc.y,m_width,m_height,lastPos);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (void)mouseUp:(NSEvent *)theEvent {
[self setNeedsDisplay:YES];
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ptov(int x, int y, int width, int height, float v[3]){
float a,d;
// project x,y onto 1/2 sphere centered within width and height
v[0] = (2.0*x - width)/ width;
v[1] = (height - 2.0*y)/ height;
d = sqrt(v[0]*v[0] + v[1]*v[1]);
v[2] = cos((PI/2)*((d < 1.0) ? d : 1.0));
a = 1.0 / sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
v[0] *=a;
v[1] *=a;
v[2] *=a;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-(void)prepareOpenGL{
if( ![ self loadGLTextures ] ){
NSLog(#"Failed to load GL Textures");
}
GLint swapInt = 1;
[[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval]; // set to vbl sync
//glEnable( GL_TEXTURE_2D ); // Enable texture mapping
glShadeModel( GL_SMOOTH ); // Enable smooth shading
glClearColor( 0.0f, 0.0f, 0.0f, 0.5f ); // Black background
glClearDepth( 1.0f ); // Depth buffer setup
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glEnable (GL_BLEND);
glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glPolygonOffset (1.0f, 1.0f);
firstOccurenceOfDrawRect = NO;
/* // set start values...
rVel[0] = 0.3; rVel[1] = 0.1; rVel[2] = 0.2;
rAccel[0] = 0.003; rAccel[1] = -0.005; rAccel[2] = 0.004;*/
[[self window] setAcceptsMouseMovedEvents: YES];
glViewport(0, 0, (GLsizei) self.bounds.size.width, (GLsizei) self.bounds.size.height);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (void) drawRect: (NSRect) rect
{
/// if (firstOccurenceOfDrawRect)
// [self initGL];
// On charge la matrice de projection pour définir ce que l'on va voir et comment
glMatrixMode(GL_PROJECTION);
// On centre
glLoadIdentity();
// On prend du recul
glOrtho(-1.0f, 1.0f, -1.5f, 1.5f, -10.0f, 10.0f);
// On efface ce qui a été dessiné auparavant
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// On va maintenant définir ce que l'on veut dessiner
glMatrixMode(GL_MODELVIEW);
// Avant de commencer à dessiner, on va affecter de deux rotations le repère des coordonnées du cube pour le faire "bouger"
glLoadIdentity();
glRotatef(angle, axis[0], axis[1], axis[2]);
// [self resizeGL]; // forces projection matrix update (does test for size changes)
// [self updateModelView];
glColor3f (1.0, 1.0, 1.0);
glDisable(GL_CULL_FACE);
glFrontFace(GL_CW);
glutSolidTeapot(200.0);
glFrontFace(GL_CCW);
glEnable(GL_TEXTURE_2D);
glBindTexture( GL_TEXTURE_2D, texture[ 0 ] ); // Select our texture
glBegin( GL_QUADS );
// Front
glTexCoord2f( 0.0f, 0.0f );
glVertex3f( -1.0f, -1.0f, 0.0f ); // Bottom left
glTexCoord2f( 1.0f, 0.0f );
glVertex3f( 1.0f, -1.0f, 0.0f ); // Bottom right
glTexCoord2f( 1.0f, 1.0f );
glVertex3f( 1.0f, 1.0f, 0.0f ); // Top right
glTexCoord2f( 0.0f, 1.0f );
glVertex3f( -1.0f, 1.0f, 0.0f ); // Top left
glEnd();
glBindTexture( GL_TEXTURE_2D, texture[ 1 ] ); // Select our texture
glBegin( GL_QUADS );
// side
glTexCoord2f( 1.0f, 0.0f );
glVertex3f( 0.0f, -1.0f, -1.0f ); // Bottom right
glTexCoord2f( 1.0f, 1.0f );
glVertex3f( 0.0f, 1.0f, -1.0f ); // Top right
glTexCoord2f( 0.0f, 1.0f );
glVertex3f( 0.0f, 1.0f, 1.0f ); // Top left
glTexCoord2f( 0.0f, 0.0f );
glVertex3f( 0.0f, -1.0f, 1.0f ); // Bottom left
glEnd();
glBindTexture( GL_TEXTURE_2D, texture[ 2 ] ); // Select our texture
glBegin( GL_QUADS );
// Top
glTexCoord2f( 0.0f, 1.0f );
glVertex3f( -1.0f, 0.0f, -1.0f ); // Top left
glTexCoord2f( 0.0f, 0.0f );
glVertex3f( -1.0f, 0.0f, 1.0f ); // Bottom left
glTexCoord2f( 1.0f, 0.0f );
glVertex3f( 1.0f, 0.0f, 1.0f ); // Bottom right
glTexCoord2f( 1.0f, 1.0f );
glVertex3f( 1.0f, 0.0f, -1.0f ); // Top right
glEnd();
glDisable(GL_TEXTURE_2D);
glColor3f (1.0, 1.0, 1.0);
glDisable(GL_CULL_FACE);
glFrontFace(GL_CW);
glutSolidTeapot(200.0);
[self postRemoteImage];
[[self openGLContext] flushBuffer];
}
Is this the entire code for the relevant methods? If so, you're never grabbing the mouse's position when you're dragging. curPos[] is uninitialized and may be returning the same values for each time you get a mouseDragged: message. This may make your object always rotate to the same position, making it appear like it's not moving.
Try inserting an NSLog in your mouseDragged: method to make sure that it's being called for your mouse drags (it probably is, but it's good to check).
There's a slight possibility that you're not giving the main run loop a chance to refresh the display, but I think that's unlikely. I've done something similar in my code and had it work just fine with everything on the main thread.
Rather than rolling your own trackball implementation, I suggest looking at Bill Dudney's trackball example code. While it is for the iPhone and deals with Core Animation, the trackball object he uses should be applicable to your case.