Stap 3: Maak de Renderer
Wij gaan volgende om te beginnen met de code die nodig is om iets renderen te krijgen. Voor dit gewijzigde ik zojuist de GLES code in de hoek-sjabloon die een draaiende kubus tekent. Dus nu een SimpleRenderer-klasse toevoegen aan een nieuwe gedeelde C++-project dat we SharedRenderer zullen noemen. Dit zal worden later ook gedeeld door de andere projecten. Ook verwijst enkel naar dit project in de Runtime-onderdelen.
Gelieve enkel start door het uitschakelen van vooraf gecompileerde headers, omdat dit momenteel niet mooi met Android speelt gedeeld C++ in VS 2015 RC. Dit is omdat C++-project van een VS-gedeelde bestanden op een Android C++ library project momenteel niet kan zien. Hier de hoop dat Microsoft bevestigt het binnenkort. U kunt dit doen door te gaan naar de eigenschappenpagina van uw hoek op zowel Win als WP en simpelweg selecteren van "Niet met behulp van gecompileerde Headers" in het veld "Voorgecompileerd Header" in de groep "C/C++".
Ik ga niet om te bespreken wat de volgende GLES code doet zoals het valt buiten het bestek van de tutorial. Zet dus gewoon de volgende in de header:
#pragma once #include <GLES2/gl2.h>
class SimpleRenderer{ public: SimpleRenderer(); ~SimpleRenderer(); void Draw(); void UpdateWindowSize(GLsizei width, GLsizei height); void Init();
private: GLuint mProgram; GLsizei mWindowWidth; GLsizei mWindowHeight;
GLint mPositionAttribLocation; GLint mColorAttribLocation;
GLint mModelUniformLocation; GLint mViewUniformLocation; GLint mProjUniformLocation;
GLuint mVertexPositionBuffer; GLuint mVertexColorBuffer; GLuint mIndexBuffer;
int mDrawCount; };
En de volgende handelingen uit in het CPP-bestand:
// This file is used by the template to render a basic scene using GL.
#include "SimpleRenderer.h" #include "MathHelper.h"
#include <vector> #include <string>
#include <GLES2/gl2.h> #include <GLES2/gl2ext.h>
#if defined(WIN_STORE) || defined(WIN_PHONE) #include <ppltasks.h>
using namespace Platform; #endif
#define STRING(s) #s
GLuint CompileShader(GLenum type, const std::string &source) { GLuint shader = glCreateShader(type);
const char *sourceArray[1] = { source.c_str() }; glShaderSource(shader, 1, sourceArray, NULL); glCompileShader(shader);
GLint compileResult; glGetShaderiv(shader, GL_COMPILE_STATUS, &compileResult);
if (compileResult == 0) { GLint infoLogLength; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
std::vector infoLog(infoLogLength); glGetShaderInfoLog(shader, (GLsizei)infoLog.size(), NULL, infoLog.data());
std::wstring errorMessage = std::wstring(L"Shader compilation failed: "); errorMessage += std::wstring(infoLog.begin(), infoLog.end());
#if defined(WIN_STORE) || defined(WIN_PHONE) throw Exception::CreateException(E_FAIL, ref new Platform::String(errorMessage.c_str())); #endif }
return shader; }
GLuint CompileProgram(const std::string &vsSource, const std::string &fsSource) { GLuint program = glCreateProgram();
if (program == 0) { #if defined(WIN_STORE) || defined(WIN_PHONE) throw Exception::CreateException(E_FAIL, L"Program creation failed"); #else return -1; #endif }
GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource); GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fsSource);
if (vs == 0 || fs == 0) { glDeleteShader(fs); glDeleteShader(vs); glDeleteProgram(program); return 0; }
glAttachShader(program, vs); glDeleteShader(vs);
glAttachShader(program, fs); glDeleteShader(fs);
glLinkProgram(program);
GLint linkStatus; glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
if (linkStatus == 0) { GLint infoLogLength; glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength);
std::vector infoLog(infoLogLength); glGetProgramInfoLog(program, (GLsizei)infoLog.size(), NULL, infoLog.data());
std::wstring errorMessage = std::wstring(L"Program link failed: "); errorMessage += std::wstring(infoLog.begin(), infoLog.end());
#if defined(WIN_STORE) || defined(WIN_PHONE) throw Exception::CreateException(E_FAIL, ref new Platform::String(errorMessage.c_str())); #else return -1; #endif }
return program; }
SimpleRenderer::SimpleRenderer() : mWindowWidth(0), mWindowHeight(0), mDrawCount(0) { }
void SimpleRenderer::Init() { // Vertex Shader source const std::string vs = STRING ( uniform mat4 uModelMatrix; uniform mat4 uViewMatrix; uniform mat4 uProjMatrix; attribute vec4 aPosition; attribute vec4 aColor; varying vec4 vColor; void main() { gl_Position = uProjMatrix * uViewMatrix * uModelMatrix * aPosition; vColor = aColor; } );
// Fragment Shader source const std::string fs = STRING ( precision mediump float; varying vec4 vColor; void main() { gl_FragColor = vColor; } );
// Set up the shader and its uniform/attribute locations. mProgram = CompileProgram(vs, fs); mPositionAttribLocation = glGetAttribLocation(mProgram, "aPosition"); mColorAttribLocation = glGetAttribLocation(mProgram, "aColor"); mModelUniformLocation = glGetUniformLocation(mProgram, "uModelMatrix"); mViewUniformLocation = glGetUniformLocation(mProgram, "uViewMatrix"); mProjUniformLocation = glGetUniformLocation(mProgram, "uProjMatrix");
// Then set up the cube geometry. GLfloat vertexPositions[] = { -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, };
glGenBuffers(1, &mVertexPositionBuffer); glBindBuffer(GL_ARRAY_BUFFER, mVertexPositionBuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(vertexPositions), vertexPositions, GL_STATIC_DRAW);
GLfloat vertexColors[] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, };
glGenBuffers(1, &mVertexColorBuffer); glBindBuffer(GL_ARRAY_BUFFER, mVertexColorBuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(vertexColors), vertexColors, GL_STATIC_DRAW);
short indices[] = { 0, 1, 2, // -x 1, 3, 2,
4, 6, 5, // +x 5, 6, 7,
0, 5, 1, // -y 0, 4, 5,
2, 7, 6, // +y 2, 3, 7,
0, 6, 4, // -z 0, 2, 6,
1, 7, 3, // +z 1, 5, 7, };
glGenBuffers(1, &mIndexBuffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); }
SimpleRenderer::~SimpleRenderer() { if (mProgram != 0) { glDeleteProgram(mProgram); mProgram = 0; }
if (mVertexPositionBuffer != 0) { glDeleteBuffers(1, &mVertexPositionBuffer); mVertexPositionBuffer = 0; }
if (mVertexColorBuffer != 0) { glDeleteBuffers(1, &mVertexColorBuffer); mVertexColorBuffer = 0; }
if (mIndexBuffer != 0) { glDeleteBuffers(1, &mIndexBuffer); mIndexBuffer = 0; } }
void SimpleRenderer::Draw() { glEnable(GL_DEPTH_TEST); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (mProgram == 0) return;
glUseProgram(mProgram);
glBindBuffer(GL_ARRAY_BUFFER, mVertexPositionBuffer); glEnableVertexAttribArray(mPositionAttribLocation); glVertexAttribPointer(mPositionAttribLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, mVertexColorBuffer); glEnableVertexAttribArray(mColorAttribLocation); glVertexAttribPointer(mColorAttribLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
MathHelper::Matrix4 modelMatrix = MathHelper::SimpleModelMatrix((float)mDrawCount / 50.0f); glUniformMatrix4fv(mModelUniformLocation, 1, GL_FALSE, &(modelMatrix.m[0][0]));
MathHelper::Matrix4 viewMatrix = MathHelper::SimpleViewMatrix(); glUniformMatrix4fv(mViewUniformLocation, 1, GL_FALSE, &(viewMatrix.m[0][0]));
MathHelper::Matrix4 projectionMatrix = MathHelper::SimpleProjectionMatrix(float(mWindowWidth) / float(mWindowHeight)); glUniformMatrix4fv(mProjUniformLocation, 1, GL_FALSE, &(projectionMatrix.m[0][0]));
// Draw 36 indices: six faces, two triangles per face, 3 indices per triangle glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer); glDrawElements(GL_TRIANGLES, (6 * 2) * 3, GL_UNSIGNED_SHORT, 0);
mDrawCount += 1; }
void SimpleRenderer::UpdateWindowSize(GLsizei width, GLsizei height) { glViewport(0, 0, width, height); mWindowWidth = width; mWindowHeight = height; }
In het SharedRenderer-project moet u ook een MathHelper.h-bestand met de volgende inhoud toe te voegen:
#pragma once // These are some simple math helpers to enable the template to render a spinning cube. It is not a complete math library. // You can replace this with your favorite math library that's suitable for your target platforms, e.g. DirectXMath or GLM.
#include <math.h>
namespace MathHelper {
struct Matrix4 { Matrix4(float m00, float m01, float m02, float m03, float m10, float m11, float m12, float m13, float m20, float m21, float m22, float m23, float m30, float m31, float m32, float m33) { m[0][0] = m00; m[0][1] = m01; m[0][2] = m02; m[0][3] = m03; m[1][0] = m10; m[1][1] = m11; m[1][2] = m12; m[1][3] = m13; m[2][0] = m20; m[2][1] = m21; m[2][2] = m22; m[2][3] = m23; m[3][0] = m30; m[3][1] = m31; m[3][2] = m32; m[3][3] = m33; }
float m[4][4]; };
inline static Matrix4 SimpleModelMatrix(float radians) { float cosine = cosf(radians); float sine = sinf(radians);
return Matrix4(cosine, 0.0f, -sine, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, sine, 0.0f, cosine, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f); }
inline static Matrix4 SimpleViewMatrix() { // Camera is at 60 degrees to the ground, in the YZ plane. // Camera Look-At is hardcoded to (0, 0, 0). // Camera Up is hardcoded to (0, 1, 0). const float sqrt3over2 = 0.86603f; const float cameraDistance = 5.0f;
return Matrix4(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, sqrt3over2, 0.5f, 0.0f, 0.0f, -0.5f, sqrt3over2, 0.0f, 0.0f, 0.0f, -cameraDistance, 1.0f); }
inline static Matrix4 SimpleProjectionMatrix(float aspectRatio) { // Far plane is at 50.0f, near plane is at 1.0f. // FoV is hardcoded to pi/3. const float cotangent = 1 / tanf(3.14159f / 6.0f);
return Matrix4(cotangent / aspectRatio, 0.0f, 0.0f, 0.0f, 0.0f, cotangent, 0.0f, 0.0f, 0.0f, 0.0f, -50.0f / (50.0f - 1.0f), (-50.0f * 1.0f) / (50.0f - 1.0f), 0.0f, 0.0f, -1.0f, 0.0f); }
}
U moet zitten kundig voor uw project nu opnieuw compileren. Als dat niet het geval is, ga terug en controleer wat u zou kunnen gemist hebben. Ik adviseer ook verwijderen van de bestanden "Class1.h" en "Class.cpp" in de Runtime-onderdelen, zoals we ze niet nodig. Net noteer de standaardnaamruimte gebruikt in hen eerst als u zult het later nodig hebben.