5 #define GLM_ENABLE_EXPERIMENTAL
\r
7 #include <glm/glm.hpp>
\r
8 #include <glm/gtx/rotate_vector.hpp>
\r
9 #include <glm/gtc/matrix_transform.hpp>
\r
10 #include <glm/gtc/type_ptr.hpp>
\r
12 #include <SFML/OpenGL.hpp>
\r
13 #include <SFML/Graphics.hpp>
\r
16 #include <imgui-SFML.h>
\r
18 #include <assimp/Importer.hpp>
\r
19 #include <assimp/postprocess.h>
\r
20 #include <assimp/scene.h>
\r
22 const char *vertexShaderSource = R"(
\r
25 layout (location = 0) in vec3 pos;
\r
26 layout (location = 1) in vec3 normal;
\r
33 uniform mat4 projection;
\r
37 gl_Position = projection * view * model * vec4(pos, 1.0);
\r
38 FragPos = vec3(model * vec4(pos, 1));
\r
43 const char *fragmentShaderSource = R"(
\r
51 uniform vec3 objectColor;
\r
52 uniform vec3 lightColor;
\r
53 uniform vec3 lightPos;
\r
57 vec3 norm = normalize(Normal);
\r
58 vec3 lightDir = normalize(lightPos - FragPos);
\r
60 float diff = max(dot(norm, lightDir), 0.0);
\r
61 vec3 diffuse = diff * lightColor;
\r
63 float ambientStrength = 0.1;
\r
64 vec3 ambient = ambientStrength * lightColor;
\r
66 vec3 result = (ambient + diffuse) * objectColor;
\r
67 FragColor = vec4(result, 1.0f);
\r
71 std::vector<float> vertices;
\r
72 std::vector<GLuint> indices;
\r
74 glm::vec3 lightPos(1.2f, 5.0f, 2.0f);
\r
76 void load(const std::string &filename, std::vector<float> &vertices,
\r
77 std::vector<GLuint> &indices) {
\r
78 Assimp::Importer importer;
\r
80 const aiScene *scene = importer.ReadFile(
\r
81 filename, aiProcess_CalcTangentSpace | aiProcess_Triangulate |
\r
82 aiProcess_SortByPType | aiProcess_GenSmoothNormals);
\r
84 for (int i = 0; i < scene->mMeshes[0]->mNumVertices; i++) {
\r
85 aiVector3D v = scene->mMeshes[0]->mVertices[i];
\r
86 aiVector3D n = scene->mMeshes[0]->mNormals[i];
\r
87 vertices.push_back(v.x);
\r
88 vertices.push_back(v.y);
\r
89 vertices.push_back(v.z);
\r
90 vertices.push_back(n.x);
\r
91 vertices.push_back(n.y);
\r
92 vertices.push_back(n.z);
\r
95 for (int i = 0; i < scene->mMeshes[0]->mNumFaces; i++) {
\r
96 aiFace f = scene->mMeshes[0]->mFaces[i];
\r
97 for (int j = 0; j < f.mNumIndices; j++) {
\r
98 indices.push_back(f.mIndices[j]);
\r
106 sf::ContextSettings settings;
\r
107 settings.depthBits = 24;
\r
108 settings.antialiasingLevel = 0;
\r
109 settings.majorVersion = 4;
\r
110 settings.minorVersion = 6;
\r
112 sf::RenderWindow window(sf::VideoMode(1600, 900), "Subsurface Scattering",
\r
113 sf::Style::Default, settings);
\r
114 window.setVerticalSyncEnabled(true);
\r
115 window.setMouseCursorGrabbed(true);
\r
116 window.setMouseCursorVisible(false);
\r
118 ImGui::SFML::Init(window);
\r
122 if (glewInit() != GLEW_OK) {
\r
125 load("models/Isotrop-upperjaw.ply", vertices, indices);
\r
129 GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
\r
130 glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
\r
131 glCompileShader(vertexShader);
\r
135 glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
\r
137 glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
\r
138 printf("Error compiling vertex shader: %s\n", infoLog);
\r
141 GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
\r
142 glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
\r
143 glCompileShader(fragmentShader);
\r
145 glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
\r
147 glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
\r
148 printf("Error compiling fragment shader: %s\n", infoLog);
\r
151 // Link Shader Program
\r
153 GLuint shaderProgram = glCreateProgram();
\r
154 glAttachShader(shaderProgram, vertexShader);
\r
155 glAttachShader(shaderProgram, fragmentShader);
\r
156 glLinkProgram(shaderProgram);
\r
158 glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
\r
160 glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
\r
161 printf("Error linking shader program: %s\n", infoLog);
\r
164 glDeleteShader(vertexShader);
\r
165 glDeleteShader(fragmentShader);
\r
170 glGenBuffers(1, &VBO);
\r
175 glGenBuffers(1, &EBO);
\r
180 glGenVertexArrays(1, &VAO);
\r
182 glBindVertexArray(VAO);
\r
184 glBindBuffer(GL_ARRAY_BUFFER, VBO);
\r
185 glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertices.size(),
\r
186 vertices.data(), GL_STATIC_DRAW);
\r
188 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
\r
189 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * indices.size(),
\r
190 indices.data(), GL_STATIC_DRAW);
\r
192 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, (void*)(0));
\r
193 glEnableVertexAttribArray(0);
\r
194 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, (void*)(sizeof(float) * 3));
\r
195 glEnableVertexAttribArray(1);
\r
197 glBindVertexArray(0);
\r
201 glm::mat4 model = glm::scale(glm::mat4(1.0f), glm::vec3(0.01f, 0.01f, 0.01f));
\r
215 glm::vec3 camPos = glm::vec3(0, 0, -3);
\r
216 glm::vec3 camForward = glm::vec3(0, 0, 1);
\r
217 glm::vec3 camUp = glm::vec3(0, 1, 0);
\r
220 glm::lookAt(glm::vec3(arcball.camX, 0.0, arcball.camZ), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
\r
223 glm::perspective(glm::radians(45.0f), (float)window.getSize().x / window.getSize().y, 0.001f, 1000.0f);
\r
226 bool catchMouse = false;
\r
227 bool wireframe = false;
\r
228 bool freecam = false;
\r
229 float radius = 1.0f;
\r
232 sf::Clock deltaClock;
\r
234 bool running = true;
\r
237 while (window.pollEvent(event)) {
\r
238 ImGui::SFML::ProcessEvent(event);
\r
240 if (event.type == sf::Event::EventType::Closed) {
\r
242 } else if (event.type == sf::Event::EventType::Resized) {
\r
243 glViewport(0, 0, event.size.width, event.size.height);
\r
244 } else if (event.type == sf::Event::EventType::KeyReleased) {
\r
245 using keys = sf::Keyboard;
\r
246 switch (event.key.code) {
\r
251 options.catchMouse = !options.catchMouse;
\r
254 freecam.mouseX = freecam.mouseY = 0;
\r
257 } else if (event.type == sf::Event::EventType::MouseWheelScrolled) {
\r
258 options.radius -= event.mouseWheelScroll.delta / 5.0f;
\r
262 int mouseDeltaX = sf::Mouse::getPosition(window).x - window.getSize().x / 2;
\r
263 int mouseDeltaY = sf::Mouse::getPosition(window).y - window.getSize().y / 2;
\r
265 if (options.catchMouse) {
\r
266 sf::Mouse::setPosition(sf::Vector2i(
\r
267 window.getSize().x / 2,
\r
268 window.getSize().y / 2
\r
271 if (options.freecam) {
\r
272 freecam.mouseX += mouseDeltaX;
\r
273 freecam.mouseY += mouseDeltaY;
\r
275 camForward = glm::rotate(glm::vec3(0, 0, 1), freecam.mouseY / 500.0f, glm::vec3(1, 0, 0));
\r
276 camForward = glm::rotate(camForward, -freecam.mouseX / 500.0f, glm::vec3(0, 1, 0));
\r
278 if (sf::Keyboard::isKeyPressed(sf::Keyboard::W)) {
\r
279 camPos += camForward / 20.0f;
\r
281 if (sf::Keyboard::isKeyPressed(sf::Keyboard::S)) {
\r
282 camPos -= camForward / 20.0f;
\r
284 if (sf::Keyboard::isKeyPressed(sf::Keyboard::A)) {
\r
285 glm::vec3 camLeft = glm::rotate(glm::vec3(0, 0, 1), -freecam.mouseX / 500.0f + glm::radians(90.0f), glm::vec3(0, 1, 0));
\r
286 camPos += camLeft / 20.0f;
\r
288 if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) {
\r
289 glm::vec3 camRight = glm::rotate(glm::vec3(0, 0, 1), -freecam.mouseX / 500.0f - glm::radians(90.0f), glm::vec3(0, 1, 0));
\r
290 camPos += camRight / 20.0f;
\r
293 if (sf::Mouse::isButtonPressed(sf::Mouse::Left)) {
\r
294 arcball.mouseX += mouseDeltaX;
\r
295 arcball.mouseY += mouseDeltaY;
\r
302 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
\r
304 glEnable(GL_DEPTH_TEST);
\r
306 if (options.wireframe)
\r
307 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
\r
309 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
\r
311 glUseProgram(shaderProgram);
\r
314 //model = glm::rotate(model, glm::radians(0.2f), glm::vec3(0.0f, 1.0f, 0.0f));
\r
316 if (options.freecam) {
\r
317 view = glm::lookAt(camPos, camPos + camForward, camUp);
\r
319 float angle = arcball.mouseY / 200.0f;
\r
320 if (angle > glm::radians(89.0f)) {
\r
321 angle = glm::radians(89.0f);
\r
322 arcball.mouseY = angle * 200.0f;
\r
324 if (angle < glm::radians(-89.0f)) {
\r
325 angle = glm::radians(-89.0f);
\r
326 arcball.mouseY = angle * 200.0f;
\r
328 arcball.camX = sin(angle) * exp(options.radius);
\r
329 arcball.camZ = cos(angle) * exp(options.radius);
\r
330 view = glm::lookAt(glm::vec3(0.0, arcball.camX, arcball.camZ), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
\r
331 view = glm::rotate(view, arcball.mouseX / 100.0f, glm::vec3(0, 1, 0));
\r
334 glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1,
\r
335 GL_FALSE, glm::value_ptr(model));
\r
336 glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "view"), 1, GL_FALSE,
\r
337 glm::value_ptr(view));
\r
338 glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "projection"), 1,
\r
339 GL_FALSE, glm::value_ptr(proj));
\r
341 glUniform3f(glGetUniformLocation(shaderProgram, "objectColor"), 1.0f, 0.5f,
\r
343 glUniform3f(glGetUniformLocation(shaderProgram, "lightColor"), 1.0f, 1.0f,
\r
345 glUniform3fv(glGetUniformLocation(shaderProgram, "lightPos"), 1, glm::value_ptr(lightPos));
\r
347 glBindVertexArray(VAO);
\r
348 glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
\r
349 glBindVertexArray(0);
\r
351 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
\r
353 ImGui::SFML::Update(window, deltaClock.restart());
\r
355 ImGui::Begin("Options");
\r
356 ImGui::LabelText("Cursor Locked", "%d", options.catchMouse);
\r
357 ImGui::Checkbox("Wireframe", &options.wireframe);
\r
358 ImGui::Checkbox("Free Cam", &options.freecam);
\r
359 if (options.freecam) {
\r
360 ImGui::LabelText("Position", "%f %f %f", camPos.x, camPos.y, camPos.z);
\r
361 ImGui::LabelText("Forward", "%f %f %f", camForward.x, camForward.y, camForward.z);
\r
362 ImGui::LabelText("Mouse", "%d %d", freecam.mouseX, freecam.mouseY);
\r
364 ImGui::LabelText("Rotation", "%f %f", arcball.camX, arcball.camZ);
\r
365 ImGui::InputFloat("Radius", &options.radius);
\r
369 ImGui::SFML::Render(window);
\r