Étape 3: Créer le moteur de rendu
Ensuite, nous allons commencer avec le code nécessaire pour obtenir quelque chose de rendu. Pour cela j’ai vient de modifier le code GLES fourni dans le modèle d’ANGLE qui dessine un cube en rotation. Alors maintenant ajouter une classe SimpleRenderer à un nouveau projet C++ partagé, que nous appellerons SharedRenderer. Ce sera plus tard également être partagée par les autres projets. Aussi juste faire référence à ce projet dans les composants d’exécution.
S’il vous plaît, il suffit de commencer par désactiver les en-têtes précompilés parce que cela ne joue pas actuellement sympa avec Android partagée C++ VS 2015 RC. C’est parce qu’actuellement un projet C++ partagé de VS ne voyez pas tous les fichiers dans un projet de bibliothèque C++ Android. En espérant que Microsoft l’arrange bientôt. Vous pouvez le faire en accédant à votre page de propriétés d’ANGLE sur Win et WP et en sélectionnant simplement « Ne pas utiliser les en-têtes précompilés » dans le champ « En-tête précompilé » dans le groupe « C/C++ ».
Je ne vais pas pour discuter de ce que le code GLES suivant fait car il déborde le cadre de ce tutoriel. Il suffit donc mettre ce qui suit dans l’en-tête :
#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; };
Et ce qui suit dans le fichier CPP :
// 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; }
Dans le projet SharedRenderer, vous devrez également ajouter un fichier MathHelper.h avec le contenu suivant :
#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); }
}
Vous devriez être en mesure de compiler votre projet à nouveau dès maintenant. Si ce n’est pas le cas, revenir en arrière et vérifiez ce que vous auriez pu manquer. Aussi, je recommande de supprimer les fichiers « Class1.h » et « Class.cpp » dans les composants d’exécution que nous n’aurez pas besoin d’eux. Il suffit d’écrire vers le bas de l’espace de noms par défaut utilisé en eux tout d’abord que vous en aurez besoin plus tard.