Added shaders got smooth min working

This commit is contained in:
Jack Christensen 2023-11-06 22:02:45 -05:00
parent db4fcead4f
commit d534be6ee1
7 changed files with 566 additions and 19 deletions

View File

@ -20,6 +20,14 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\Application.cpp" />
<ClCompile Include="src\Camera.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="shaders\parade_fs.glsl" />
<None Include="shaders\parade_vs.glsl" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\Camera.h" />
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
@ -96,8 +104,8 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)bin\$(Platform)$(Configuration)</OutDir>
<IntDir>$(SolutionDir)bin\intermediates\$(Platform)$(Configuration)</IntDir>
<OutDir>$(SolutionDir)bin\$(Platform)$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)bin\intermediates\$(Platform)$(Configuration)\</IntDir>
<LibraryPath>$(SolutionDir)\lib;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64)</LibraryPath>
<IncludePath>$(SolutionDir)\imgui-master;$(SolutionDir)\include;$(SolutionDir)\imgui_master;$(IncludePath)</IncludePath>
</PropertyGroup>

View File

@ -13,10 +13,29 @@
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="Shaders">
<UniqueIdentifier>{de7b03ae-538e-4924-978f-dbbf7fd055af}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\Application.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\Camera.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="shaders\parade_vs.glsl">
<Filter>Shaders</Filter>
</None>
<None Include="shaders\parade_fs.glsl">
<Filter>Shaders</Filter>
</None>
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\Camera.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

29
include/Camera.h Normal file
View File

@ -0,0 +1,29 @@
#pragma once
#include <glm/glm.hpp>
class Camera
{
private:
glm::vec3 m_position = { 0.f, 0.f, 1.f };
glm::vec3 m_front = { 0.f, 0.f, 0.f };
glm::vec3 m_up = { 0.f, 1.f, 0.f };
glm::vec3 m_right = { 1.f, 0.f, 0.f };
public:
// Since all variables are dependent on each other I've decided to
// disable the setters until I make sure they don't break things
// glm::vec3& position() { return m_position; }
// glm::vec3& front() { return m_front; }
// glm::vec3& up() { return m_up; }
// glm::vec3& right() { return m_right; }
const glm::vec3& position() const { return m_position; }
const glm::vec3& front() const { return m_front; }
const glm::vec3& up() const { return m_up; }
const glm::vec3& right() const { return m_right; }
void pan(float dist_x, float dist_y);
void orbit(float yaw, float pitch);
void zoom(float dist);
};

169
shaders/parade_fs.glsl Normal file
View File

@ -0,0 +1,169 @@
#version 400
uniform mat4 P;
uniform mat4 V;
uniform mat4 M;
uniform vec3 cam_pos;
uniform int window_width;
uniform int window_height;
uniform vec3 la;
uniform vec3 ld;
uniform vec3 ls;
uniform vec3 ka;
uniform vec3 kd;
uniform vec3 ks;
in vec3 v_pos;
out vec4 FragColor;
struct Torus
{
float R;
float r;
};
Torus torus;
struct Sphere
{
vec3 center;
float r;
};
Sphere sphere;
void initTorus()
{
torus.R = 0.5;
torus.r = 0.15;
}
void initSphere()
{
sphere.center = vec3(0.0, 0.25, 0.0);
sphere.r = 0.25;
}
float sphereSDF(vec3 p, vec3 center, float r) {
return length(p - center) - r;
}
float torusSDF(vec3 p, float R, float r) {
vec2 q = vec2(length(p.xz) - R, p.y);
return length(q) - r;
}
vec3 estimateNormalsSphere(vec3 p)
{
float epsilon = 0.001;
float x = sphereSDF(vec3(p.x + epsilon, p.y, p.z), sphere.center, sphere.r) - sphereSDF(vec3(p.x - epsilon, p.y, p.z), sphere.center, sphere.r);
float y = sphereSDF(vec3(p.x, p.y + epsilon, p.z), sphere.center, sphere.r) - sphereSDF(vec3(p.x, p.y - epsilon, p.z), sphere.center, sphere.r);
float z = sphereSDF(vec3(p.x, p.y, p.z + epsilon), sphere.center, sphere.r) - sphereSDF(vec3(p.x, p.y, p.z - epsilon), sphere.center, sphere.r);
return normalize(vec3(x, y, z));
}
vec3 estimateNormalsTorus(vec3 p)
{
float epsilon = 0.001;
float x = torusSDF(vec3(p.x + epsilon, p.y, p.z), torus.R, torus.r) - torusSDF(vec3(p.x - epsilon, p.y, p.z), torus.R, torus.r);
float y = torusSDF(vec3(p.x, p.y + epsilon, p.z), torus.R, torus.r) - torusSDF(vec3(p.x, p.y - epsilon, p.z), torus.R, torus.r);
float z = torusSDF(vec3(p.x, p.y, p.z + epsilon), torus.R, torus.r) - torusSDF(vec3(p.x, p.y, p.z - epsilon), torus.R, torus.r);
return normalize(vec3(x, y, z));
}
float smoothMinSDF(float d1, float d2, float k) {
float h = max(k - abs(d1 - d2), 0) / k;
return min(d1, d2) - h * h * h * k * 1.0 / 6.0;
}
float smoothMaxSDF(float d1, float d2, float k) {
float h = clamp(0.5 + 0.5 * (d2 - d1) / k, 0.0, 1.0);
return mix(d2, d1, h) - k * h * (1.0 - h);
}
float blendSDF(float d1, float d2) {
return (d1 * d2) / (d1 + d2);
}
vec3 estimateSmoothNormals(vec3 p, float smoothness) {
float epsilon = 0.001;
float d = smoothMinSDF(torusSDF(p, torus.R, torus.r), sphereSDF(p, sphere.center, sphere.r), smoothness);
float nx = smoothMinSDF(torusSDF(vec3(p.x + epsilon, p.y, p.z), torus.R, torus.r), sphereSDF(vec3(p.x + epsilon, p.y, p.z), sphere.center, sphere.r), smoothness) - d;
float ny = smoothMinSDF(torusSDF(vec3(p.x, p.y + epsilon, p.z), torus.R, torus.r), sphereSDF(vec3(p.x, p.y + epsilon, p.z), sphere.center, sphere.r), smoothness) - d;
float nz = smoothMinSDF(torusSDF(vec3(p.x, p.y, p.z + epsilon), torus.R, torus.r), sphereSDF(vec3(p.x, p.y, p.z + epsilon), sphere.center, sphere.r), smoothness) - d;
return normalize(vec3(nx, ny, nz));
}
void main(void)
{
vec3 normals;
vec3 color = la;
vec4 ray_pos = vec4(cam_pos, 1.0);
float ray_dist = 0.0;
float max_dist = 100.0;
float epsilon = 0.001;
int steps = 0;
int max_steps = 1000;
vec3 light_pos = vec3(0.0, 1.0, 0.0);
int spec_exponent = 40;
initTorus();
initSphere();
vec2 ndc_pos = 2.0 * vec2(gl_FragCoord.x / window_width, gl_FragCoord.y / window_height) - 1.0;
vec4 cam_dir = inverse(P) * vec4(ndc_pos, 1.0, 1.0);
cam_dir /= cam_dir.w;
cam_dir = vec4(cam_dir.xyz, 0.0);
vec4 ray_dir = normalize(inverse(V) * cam_dir);
while (ray_dist < max_dist && steps < max_steps)
{
steps++;
float distTorus = torusSDF(ray_pos.xyz, torus.R, torus.r);
float distSphere = sphereSDF(ray_pos.xyz, sphere.center, sphere.r);
float minDist = smoothMinSDF(distTorus, distSphere, 1.0);
//bool isTorus = distTorus < distSphere;
//float minDist = min(distTorus, distSphere);
if (minDist <= epsilon)
{
vec4 ambient_color, diffuse_color;
ambient_color = vec4(ka, 1.0);
diffuse_color = vec4(kd, 1.0);
vec4 ambient = vec4(la, 1.0) * ambient_color;
normals = estimateSmoothNormals(ray_pos.xyz, 1.0);
//if (isTorus)
// normals = estimateNormalsTorus(ray_pos.xyz);
//else
// normals = estimateNormalsSphere(ray_pos.xyz);
vec3 nw = normalize(normals);
vec3 lw = normalize(light_pos - ray_pos.xyz);
float dist = length(vec4(ray_pos.xyz - light_pos, 1.0));
vec4 diffuse = max(dot(nw, lw), 0) * diffuse_color * vec4(ld, 1.0);
float spec;
vec3 vw = normalize(cam_pos - ray_pos.xyz);
vec3 halfwayDir = normalize(lw + vw);
spec = pow(max(dot(halfwayDir, nw), 0), spec_exponent);
vec4 specular = spec * vec4(ks * ls, 1.0);
color = (ambient + (1.0 / (dist * dist) * (diffuse + specular))).xyz;
break;
}
ray_pos += ray_dir * minDist;
ray_dist += minDist;
}
FragColor = vec4(color, 1.0);
}

15
shaders/parade_vs.glsl Normal file
View File

@ -0,0 +1,15 @@
#version 400
uniform mat4 P;
uniform mat4 V;
uniform mat4 M;
layout(location = 0) in vec3 pos_attrib;
out vec3 v_pos;
void main(void)
{
gl_Position = vec4(pos_attrib, 1.0);
//v_pos = pos_attrib;
}

View File

@ -1,8 +1,152 @@
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <Camera.h>
float vertices[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};
float canvas[] = {
-1.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
1.0f, -1.0f, 0.0f
};
unsigned int VBO;
unsigned int VAO;
namespace window
{
int size[] = { 800, 600 };
}
namespace scene
{
Camera camera;
unsigned int shader = -1;
float angle = glm::pi<float>() / 2.0;
float yaw = -90.f;
float pitch = 0.f;
glm::vec3 Lp = { 0.f, 1.f, 0.f }; // Light position
glm::vec3 La = { 124.0 / 255.0, 114.0 / 255.0, 160.0 / 255.0 }; // Light ambient color
glm::vec3 Ld = { 1.f, 1.f, 1.f }; // Light diffuse color
glm::vec3 Ls = { 1.f, 1.f, 1.f }; // Light specular color
glm::vec3 ka = { 0.25f, 0.25f, 0.25f }; // Object ambient color
glm::vec3 kd = { 193.0 / 255.0, 41.0 / 255.0, 46.0 / 255.0 }; // Object diffuse color
glm::vec3 ks = { 1.0f, 1.0f, 1.0f }; // Object specular color
int specular_exponent = 10.f;
}
namespace mouse
{
bool altPressed = false;
double xlast;
double ylast;
double xoffset;
double yoffset;
float sensitivity = 0.1f;
}
//Create a NULL-terminated string by reading the provided file
static char* ReadShaderSource(const char* shaderFile)
{
std::ifstream ifs(shaderFile, std::ios::in | std::ios::binary | std::ios::ate);
if (ifs.is_open())
{
unsigned int filesize = static_cast<unsigned int>(ifs.tellg());
ifs.seekg(0, std::ios::beg);
char* bytes = new char[filesize + 1];
memset(bytes, 0, filesize + 1);
ifs.read(bytes, filesize);
ifs.close();
return bytes;
}
return NULL;
}
static unsigned int CompileShader(unsigned int type, const std::string& source)
{
unsigned int id = glCreateShader(type);
const char* src = source.c_str();
glShaderSource(id, 1, &src, nullptr);
glCompileShader(id);
int result;
glGetShaderiv(id, GL_COMPILE_STATUS, &result);
if (result == GL_FALSE)
{
int length;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
char* message = (char*)alloca(length * sizeof(char));
glGetShaderInfoLog(id, length, &length, message);
std::cout << "Failed to compile " << (type == GL_VERTEX_SHADER ? "vertex" : "fragment") << " shader!" << std::endl;
std::cout << message << std::endl;
glDeleteShader(id);
return 0;
}
return id;
}
static unsigned int CreateShader(const std::string& vertexShaderFile, const std::string& fragmentShaderFile)
{
std::string vertexShader = ReadShaderSource(vertexShaderFile.c_str());
std::string fragmentShader = ReadShaderSource(fragmentShaderFile.c_str());
GLuint program = glCreateProgram();
unsigned int vs = CompileShader(GL_VERTEX_SHADER, vertexShader);
unsigned int fs = CompileShader(GL_FRAGMENT_SHADER, fragmentShader);
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program);
glValidateProgram(program);
glDeleteShader(vs);
glDeleteShader(fs);
return program;
}
void InitCanvas()
{
glBindAttribLocation(scene::shader, 0, "pos_attrib");
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(canvas), canvas, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, 0, 0, 0);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
void idle()
{
glEnable(GL_DEPTH_TEST);
@ -10,10 +154,61 @@ void idle()
void display(GLFWwindow* window)
{
glfwSwapBuffers(window);
glClearColor(0.1f, 0.1f, 0.18f, 1.0f);
glClearColor(1.0f, 0.f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glm::mat4 M = glm::rotate(scene::angle, glm::vec3(0.0f, 0.0f, 1.0f));
glm::mat4 V = glm::lookAt(scene::camera.position(), scene::camera.front(), scene::camera.up());
glm::mat4 P = glm::perspective(glm::pi<float>() / 2.0f, (float)window::size[0] / (float)window::size[1], 0.1f, 100.0f);
glViewport(0, 0, window::size[0], window::size[1]);
int P_loc = glGetUniformLocation(scene::shader, "P");
if (P_loc != -1)
{
glUniformMatrix4fv(P_loc, 1, false, glm::value_ptr(P));
}
int V_loc = glGetUniformLocation(scene::shader, "V");
if (V_loc != -1)
{
glUniformMatrix4fv(V_loc, 1, false, glm::value_ptr(V));
}
int M_loc = glGetUniformLocation(scene::shader, "M");
if (M_loc != -1)
{
glUniformMatrix4fv(M_loc, 1, false, glm::value_ptr(M));
}
int cam_pos_loc = glGetUniformLocation(scene::shader, "cam_pos");
if (cam_pos_loc != -1)
{
glUniform3fv(cam_pos_loc, 1, glm::value_ptr(scene::camera.position()));
}
int window_width_loc = glGetUniformLocation(scene::shader, "window_width");
if (window_width_loc != -1)
{
glUniform1i(window_width_loc, window::size[0]);
}
int window_height_loc = glGetUniformLocation(scene::shader, "window_height");
if (window_height_loc != -1)
{
glUniform1i(window_height_loc, window::size[1]);
}
glUniform3fv(glGetUniformLocation(scene::shader, "light_pos"), 1, glm::value_ptr(scene::Lp));
glUniform3fv(glGetUniformLocation(scene::shader, "la"), 1, glm::value_ptr(scene::La));
glUniform3fv(glGetUniformLocation(scene::shader, "ld"), 1, glm::value_ptr(scene::Ld));
glUniform3fv(glGetUniformLocation(scene::shader, "ls"), 1, glm::value_ptr(scene::Ls));
glUniform3fv(glGetUniformLocation(scene::shader, "ka"), 1, glm::value_ptr(scene::ka));
glUniform3fv(glGetUniformLocation(scene::shader, "kd"), 1, glm::value_ptr(scene::kd));
glUniform3fv(glGetUniformLocation(scene::shader, "ks"), 1, glm::value_ptr(scene::ks));
glUniform1i(glGetUniformLocation(scene::shader, "spec_exponent"), scene::specular_exponent);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLE_STRIP, 0, sizeof(vertices) / 3);
glfwSwapBuffers(window);
}
void keyboard_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
@ -25,27 +220,105 @@ void keyboard_callback(GLFWwindow* window, int key, int scancode, int action, in
case GLFW_KEY_ESCAPE:
glfwSetWindowShouldClose(window, GLFW_TRUE);
break;
case GLFW_KEY_LEFT_ALT:
mouse::altPressed = true;
break;
case GLFW_KEY_RIGHT_ALT:
mouse::altPressed = true;
break;
}
}
if (action == GLFW_RELEASE)
{
switch (key)
{
case GLFW_KEY_LEFT_ALT:
mouse::altPressed = false;
break;
case GLFW_KEY_RIGHT_ALT:
mouse::altPressed = false;
break;
}
}
}
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
void orbit_camera()
{
glViewport(0, 0, width, height);
scene::yaw += mouse::xoffset;
scene::pitch += mouse::yoffset;
scene::camera.orbit(scene::yaw, scene::pitch);
}
void pan_camera()
{
float translateSensitivity = 0.02;
scene::camera.pan((float)mouse::xoffset * -translateSensitivity, (float)mouse::yoffset * translateSensitivity);
}
void zoom_camera()
{
scene::camera.zoom((float)mouse::yoffset * 0.01f);
}
void cursor_offset(double xcurrent, double ycurrent)
{
mouse::xoffset = xcurrent - mouse::xlast;
mouse::yoffset = ycurrent - mouse::ylast;
mouse::xlast = xcurrent;
mouse::ylast = ycurrent;
mouse::xoffset *= mouse::sensitivity;
mouse::yoffset *= mouse::sensitivity;
}
//This function gets called when the mouse moves over the window.
void cursor_pos_callback(GLFWwindow* window, double x, double y)
{
if (mouse::altPressed)
{
cursor_offset(x, y);
if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS) orbit_camera();
if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS) pan_camera();
if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS) zoom_camera();
}
}
//This function gets called when a mouse button is pressed.
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
{
//std::cout << "button : " << button << ", action: " << action << ", mods: " << mods << std::endl;
if (action == GLFW_PRESS) glfwGetCursorPos(window, &mouse::xlast, &mouse::ylast);
}
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{
scene::camera.zoom((float)yoffset * -0.1f);
}
//void framebuffer_size_callback(GLFWwindow* window, int width, int height)
//{
// window::size[0] = width;
// window::size[1] = height;
// glViewport(0, 0, width, height);
//}
void window_size_callback(GLFWwindow* window, int width, int height)
{
window::size[0] = width;
window::size[1] = height;
}
void init()
{
float vertices[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};
glewInit();
scene::shader = CreateShader("shaders/parade_vs.glsl", "shaders/parade_fs.glsl");
glUseProgram(scene::shader);
unsigned int VBO;
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
InitCanvas();
}
int main()
@ -55,7 +328,7 @@ int main()
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow* window = glfwCreateWindow(800, 600, "Parade", nullptr, nullptr);
GLFWwindow* window = glfwCreateWindow(window::size[0], window::size[1], "Parade", nullptr, nullptr);
if (window == nullptr)
{
std::cout << "Failed to create window" << std::endl;
@ -64,10 +337,13 @@ int main()
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
//glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
glfwSetKeyCallback(window, keyboard_callback);
glfwSetCursorPosCallback(window, cursor_pos_callback);
glfwSetMouseButtonCallback(window, mouse_button_callback);
glfwSetScrollCallback(window, scroll_callback);
glfwSetWindowSizeCallback(window, window_size_callback);
glewInit();
init();
while (!glfwWindowShouldClose(window))

31
src/Camera.cpp Normal file
View File

@ -0,0 +1,31 @@
#include "Camera.h"
void Camera::pan(float dist_x, float dist_y) {
m_front += m_right * dist_x;
m_position += m_right * dist_x;
m_front += m_up * dist_y;
m_position += m_up * dist_y;
}
void Camera::orbit(float yaw, float pitch) {
glm::vec3 direction;
direction.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch));
direction.y = -sin(glm::radians(pitch));
direction.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch));
m_right.x = cos(glm::radians(yaw + 90.f));
m_right.z = sin(glm::radians(yaw + 90.f));
m_right = glm::normalize(m_right);
m_position = m_front - glm::normalize(direction) * glm::length(m_position - m_front);
m_up = glm::cross(m_right, glm::normalize(m_front - m_position));
}
void Camera::zoom(float dist) {
m_position += (m_position - m_front) * dist;
if (glm::length(m_position - m_front) > 100.f) {
m_position = glm::normalize(m_position) * 100.f + m_front;
}
}