it does something
This commit is contained in:
+4
-4
@@ -10,8 +10,8 @@ int main()
|
||||
Window window(1920, 1080);
|
||||
scene.startRender(
|
||||
Camera{
|
||||
.position = glm::vec3(0, 10, 10),
|
||||
.direction = glm::vec3(0, -1, -1),
|
||||
.position = glm::vec3(5, 5, 5),
|
||||
.direction = glm::vec3(-1, -1, -1),
|
||||
},
|
||||
RenderParameter{
|
||||
.width = 1920,
|
||||
@@ -25,8 +25,8 @@ int main()
|
||||
{
|
||||
scene.startRender(
|
||||
Camera{
|
||||
.position = glm::vec3(0, 10, 10),
|
||||
.direction = glm::vec3(0, -1, -1),
|
||||
.position = glm::vec3(5, 5, 5),
|
||||
.direction = glm::vec3(-1, -1, -1),
|
||||
},
|
||||
RenderParameter{
|
||||
.width = 1920,
|
||||
|
||||
+11
-12
@@ -6,9 +6,9 @@
|
||||
|
||||
Renderer::Renderer()
|
||||
{
|
||||
bvh.addPointLight(PointLight{
|
||||
.position = glm::vec3(2, 0, 2),
|
||||
.color = glm::vec3(0, 1, 0),
|
||||
bvh.addDirectionalLight(DirectionalLight{
|
||||
.direction = glm::normalize(glm::vec3(-0.4f, -0.2f, -0.6f)),
|
||||
.color = glm::vec3(1, 1, 1),
|
||||
});
|
||||
bvh.addModels(ModelLoader::loadModel("../res/models/cube.fbx"),
|
||||
glm::mat4(glm::vec4(1.0f, 0.0f, 0.0f, 0.0f), glm::vec4(0.0f, 1.0f, 0.0f, 0.0f), glm::vec4(0.0f, 0.0f, 1.0f, 0.0f),
|
||||
@@ -40,6 +40,8 @@ glm::vec3 rand01(glm::uvec3 x)
|
||||
return glm::vec3(x) * (1.0f / float(0xffffffffU));
|
||||
}
|
||||
|
||||
thread_local glm::vec3 rnd01;
|
||||
|
||||
void Renderer::render(Camera camera, RenderParameter params)
|
||||
{
|
||||
for (int samp = 0; samp < params.numSamples; ++samp)
|
||||
@@ -64,8 +66,8 @@ void Renderer::render(Camera camera, RenderParameter params)
|
||||
|
||||
//-- sample sensor
|
||||
glm::uvec2 pix = glm::uvec2(w, h);
|
||||
glm::vec3 rnd1 = rand01(glm::uvec3(pix, samp));
|
||||
glm::vec2 rnd2 = 2.0f * glm::vec2(rnd1); // vvv tent filter sample
|
||||
rnd01 = rand01(glm::uvec3(pix, samp));
|
||||
glm::vec2 rnd2 = 2.0f * glm::vec2(rnd01); // vvv tent filter sample
|
||||
glm::vec2 tent =
|
||||
glm::vec2(rnd2.x < 1 ? sqrt(rnd2.x) - 1 : 1 - sqrt(2 - rnd2.x), rnd2.y < 1 ? sqrt(rnd2.y) - 1 : 1 - sqrt(2 - rnd2.y));
|
||||
glm::vec2 s =
|
||||
@@ -82,20 +84,17 @@ void Renderer::render(Camera camera, RenderParameter params)
|
||||
glm::vec3 lensX = glm::cross(lensN, glm::vec3(0, 1, 0)); // the exact vector doesnt matter
|
||||
glm::vec3 lensY = glm::cross(lensN, lensX);
|
||||
|
||||
glm::vec3 lensSample = lensP + rnd1.x * camera.A * lensX + rnd1.y * camera.A * lensY;
|
||||
glm::vec3 lensSample = lensP + rnd01.x * camera.A * lensX + rnd01.y * camera.A * lensY;
|
||||
|
||||
glm::vec3 focalPoint = cam.origin + (camera.S_O + S_I) * cam.direction;
|
||||
float t = glm::dot(focalPoint - r.origin, lensN) / glm::dot(r.direction, lensN);
|
||||
glm::vec3 focus = r.origin + t * r.direction;
|
||||
r = Ray(lensSample, normalize(focus - lensSample)); // TODO: Fix lens
|
||||
|
||||
auto intersection = bvh.traceRay(r);
|
||||
Payload payload;
|
||||
bvh.traceRay(r, payload, 1e-4, 1e20);
|
||||
|
||||
if (intersection.has_value())
|
||||
{
|
||||
|
||||
accumulator[w + h * params.width] = intersection->shadingInfo.albedo;
|
||||
}
|
||||
accumulator[w + h * params.width] += payload.accumulatedRadiance / float(params.numSamples);
|
||||
}
|
||||
co_return;
|
||||
}(w, samp));
|
||||
|
||||
+144
-40
@@ -1,5 +1,6 @@
|
||||
#include "Scene.h"
|
||||
#include <algorithm>
|
||||
#include <numbers>
|
||||
#include <ranges>
|
||||
|
||||
void Scene::addModel(PModel model, glm::mat4 transform)
|
||||
@@ -36,7 +37,8 @@ void Scene::generate()
|
||||
for (uint32_t i = 0; i < model->indices.size(); ++i)
|
||||
{
|
||||
indicesPool.push_back(model->indices[i]);
|
||||
edgesPool.push_back(model->edges[i]);
|
||||
edgesPool.push_back(model->edges[i * 2 + 0]);
|
||||
edgesPool.push_back(model->edges[i * 2 + 1]);
|
||||
faceNormalsPool.push_back(model->faceNormals[i]);
|
||||
}
|
||||
pendingNodes.push_back(std::make_unique<Node>(model->boundingBox, ref));
|
||||
@@ -73,9 +75,11 @@ void Scene::generate()
|
||||
hierarchy = std::move(pendingNodes[0]);
|
||||
}
|
||||
|
||||
std::optional<IntersectionInfo> Scene::traceRay(Ray ray) const
|
||||
extern glm::vec3 rnd01;
|
||||
|
||||
void Scene::traceRay(Ray ray, Payload& payload, const float tmin, const float tmax) const noexcept
|
||||
{
|
||||
auto results = generateIntersections(hierarchy, ray);
|
||||
auto results = generateIntersections(hierarchy, ray, tmin, tmax);
|
||||
float closestT = std::numeric_limits<float>::max();
|
||||
IntersectionInfo info;
|
||||
for (uint32_t i = 0; i < results.size(); ++i)
|
||||
@@ -88,31 +92,85 @@ std::optional<IntersectionInfo> Scene::traceRay(Ray ray) const
|
||||
}
|
||||
if (closestT < std::numeric_limits<float>::max())
|
||||
{
|
||||
return info;
|
||||
// russian roulette ray termination
|
||||
float p = std::max(std::max(info.brdf.albedo.x, info.brdf.albedo.y), info.brdf.albedo.z);
|
||||
if (payload.depth > 5)
|
||||
{
|
||||
if (rnd01.z >= p)
|
||||
return;
|
||||
else
|
||||
payload.accumulatedMaterial /= p;
|
||||
}
|
||||
// emissive
|
||||
payload.accumulatedRadiance += payload.accumulatedMaterial * info.brdf.emissive * payload.emissive;
|
||||
payload.accumulatedMaterial *= info.brdf.albedo;
|
||||
|
||||
// direct lighting
|
||||
for (const auto& d : directionalLights)
|
||||
{
|
||||
// if there is an intersection, the light is occluded so no lighting
|
||||
if (!testIntersection(hierarchy, Ray(info.hitInfo.position, -d.direction), 1e-4, 1e20))
|
||||
{
|
||||
payload.accumulatedRadiance += info.brdf.evaluate(info.hitInfo, -ray.direction, d.direction, d.color);
|
||||
}
|
||||
}
|
||||
for (const auto& p : pointLights)
|
||||
{
|
||||
glm::vec3 lightDir = p.position - info.hitInfo.position;
|
||||
// if (!testIntersection(hierarchy, Ray(info.hitInfo.position, -lightDir), 1e-4, 1))
|
||||
{
|
||||
float d = glm::length(lightDir);
|
||||
float illuminance = std::max(1 - d / p.attenuation, 0.0f);
|
||||
|
||||
payload.accumulatedRadiance += illuminance * info.brdf.evaluate(info.hitInfo, -ray.direction, lightDir, p.color);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Next Event Estimation for mesh lights
|
||||
|
||||
// indirect lighting
|
||||
float r1 = 2 * std::numbers::pi * rnd01.x;
|
||||
float r2 = rnd01.y;
|
||||
float r2s = sqrt(r2);
|
||||
glm::vec3 w = info.hitInfo.normalLight;
|
||||
glm::vec3 u = glm::normalize(glm::cross(std::abs(w.x) > 0.1 ? glm::vec3(0, 1, 0) : glm::vec3(1, 0, 0), w));
|
||||
glm::vec3 v = glm::cross(w, u);
|
||||
ray = Ray(info.hitInfo.position, glm::normalize(u * cos(r1) * r2s + v * sin(r1) * r2s + w * sqrt(1 - r2)));
|
||||
payload.emissive = 0;
|
||||
payload.depth++;
|
||||
traceRay(ray, payload, tmin, tmax);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<IntersectionInfo> Scene::generateIntersections(const PNode& currentNode, Ray ray) const
|
||||
bool Scene::testIntersection(const PNode& currentNode, const Ray ray, const float tmin, float tmax) const noexcept
|
||||
{
|
||||
if (!currentNode->aabb.intersects(ray, 0, std::numeric_limits<float>::max()))
|
||||
if (!currentNode->aabb.intersects(ray, tmin, tmax))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (currentNode->model.numIndices > 0)
|
||||
{
|
||||
return testModel(currentNode->model, ray, tmin, tmax);
|
||||
}
|
||||
auto leftResults = testIntersection(currentNode->left, ray, tmin, tmax);
|
||||
auto rightResults = testIntersection(currentNode->right, ray, tmin, tmax);
|
||||
|
||||
return leftResults || rightResults;
|
||||
}
|
||||
|
||||
std::vector<IntersectionInfo> Scene::generateIntersections(const PNode& currentNode, const Ray ray, const float tmin,
|
||||
float tmax) const noexcept
|
||||
{
|
||||
if (!currentNode->aabb.intersects(ray, tmin, tmax))
|
||||
{
|
||||
return {};
|
||||
}
|
||||
if (currentNode->model.numIndices > 0)
|
||||
{
|
||||
auto result = intersectModel(currentNode->model, ray);
|
||||
if (result.has_value())
|
||||
{
|
||||
return {*result};
|
||||
}
|
||||
else
|
||||
{
|
||||
return {};
|
||||
}
|
||||
return intersectModel(currentNode->model, ray, tmin, tmax);
|
||||
}
|
||||
auto leftResults = generateIntersections(currentNode->left, ray);
|
||||
auto rightResults = generateIntersections(currentNode->right, ray);
|
||||
auto leftResults = generateIntersections(currentNode->left, ray, tmin, tmax);
|
||||
auto rightResults = generateIntersections(currentNode->right, ray, tmin, tmax);
|
||||
|
||||
for (auto& it : rightResults)
|
||||
{
|
||||
@@ -121,9 +179,8 @@ std::vector<IntersectionInfo> Scene::generateIntersections(const PNode& currentN
|
||||
return leftResults;
|
||||
}
|
||||
|
||||
std::optional<IntersectionInfo> Scene::intersectModel(const ModelReference& reference, const Ray ray) const
|
||||
bool Scene::testModel(const ModelReference& reference, const Ray ray, const float tmin, float tmax) const noexcept
|
||||
{
|
||||
std::optional<IntersectionInfo> intersection = {};
|
||||
float distance = 0;
|
||||
|
||||
for (size_t posIndex = 0, edgeIndex = 0, normalIndex = 0; posIndex < reference.numIndices; posIndex++, edgeIndex += 2, normalIndex++)
|
||||
@@ -163,28 +220,75 @@ std::optional<IntersectionInfo> Scene::intersectModel(const ModelReference& refe
|
||||
if (resultVector.z < 0 || resultVector.z > 1)
|
||||
continue;
|
||||
|
||||
if (resultVector.x < 1e-6)
|
||||
if (resultVector.x < tmin || resultVector.x > tmax)
|
||||
continue;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
std::vector<IntersectionInfo> Scene::intersectModel(const ModelReference& reference, const Ray ray, const float tmin,
|
||||
float tmax) const noexcept
|
||||
{
|
||||
std::vector<IntersectionInfo> intersection = {};
|
||||
float distance = 0;
|
||||
|
||||
for (size_t posIndex = 0, edgeIndex = 0, normalIndex = 0; posIndex < reference.numIndices; posIndex++, edgeIndex += 2, normalIndex++)
|
||||
{
|
||||
const auto i0 = indicesPool[reference.indicesOffset + posIndex].x;
|
||||
const auto i1 = indicesPool[reference.indicesOffset + posIndex].y;
|
||||
const auto i2 = indicesPool[reference.indicesOffset + posIndex].z;
|
||||
|
||||
const auto& p0 = positionPool[reference.positionOffset + i0];
|
||||
const auto& p1 = positionPool[reference.positionOffset + i1];
|
||||
const auto& p2 = positionPool[reference.positionOffset + i2];
|
||||
|
||||
const auto& t0 = texCoordsPool[reference.positionOffset + i0];
|
||||
const auto& t1 = texCoordsPool[reference.positionOffset + i1];
|
||||
const auto& t2 = texCoordsPool[reference.positionOffset + i2];
|
||||
|
||||
const auto& e0 = edgesPool[reference.indicesOffset + edgeIndex];
|
||||
const auto& e1 = edgesPool[reference.indicesOffset + edgeIndex + 1];
|
||||
|
||||
const auto& n = faceNormalsPool[reference.indicesOffset + normalIndex];
|
||||
|
||||
const auto s = ray.origin - p0;
|
||||
const auto s1 = glm::cross(ray.direction, e1);
|
||||
const auto s2 = glm::cross(s, e0);
|
||||
|
||||
const float fraction = 1.0f / glm::dot(s1, e0);
|
||||
const auto resultVector = glm::vec3(glm::dot(s2, e1), glm::dot(s1, s), glm::dot(s2, ray.direction)) * fraction;
|
||||
|
||||
const float b3 = 1.0f - resultVector.y - resultVector.z;
|
||||
|
||||
const auto texCoords = t0 * resultVector.y + t1 * resultVector.z + t2 * b3;
|
||||
|
||||
if (b3 < 0 || b3 > 1)
|
||||
continue;
|
||||
if (resultVector.y < 0 || resultVector.y > 1)
|
||||
continue;
|
||||
if (resultVector.z < 0 || resultVector.z > 1)
|
||||
continue;
|
||||
|
||||
if (!intersection.has_value() || resultVector.x < distance)
|
||||
{
|
||||
intersection = IntersectionInfo{
|
||||
.hitInfo =
|
||||
{
|
||||
.t = resultVector.x,
|
||||
.position = ray.origin + ray.direction * resultVector.x,
|
||||
.normal = n,
|
||||
.texCoords = texCoords,
|
||||
},
|
||||
.shadingInfo =
|
||||
{
|
||||
.albedo = glm::vec3(texCoords, 0.0f),
|
||||
.emissive = glm::vec3(0.0f, 0.0f, 0.0f),
|
||||
.type = MaterialType::DIFFUSE,
|
||||
},
|
||||
};
|
||||
distance = resultVector.x;
|
||||
}
|
||||
if (resultVector.x < tmin || resultVector.x > tmax)
|
||||
continue;
|
||||
|
||||
intersection.push_back(IntersectionInfo{
|
||||
.hitInfo =
|
||||
{
|
||||
.t = resultVector.x,
|
||||
.position = ray.origin + ray.direction * resultVector.x,
|
||||
.normal = n,
|
||||
.normalLight = n, // todo: flip based on something, idk what
|
||||
.texCoords = texCoords,
|
||||
},
|
||||
.brdf =
|
||||
{
|
||||
.albedo = glm::vec3(texCoords, 0.0f),
|
||||
.emissive = glm::vec3(0.0f, 0.0f, 0.0f),
|
||||
},
|
||||
});
|
||||
distance = resultVector.x;
|
||||
}
|
||||
|
||||
return intersection;
|
||||
|
||||
+13
-10
@@ -15,27 +15,27 @@ struct ModelReference
|
||||
|
||||
struct PointLight
|
||||
{
|
||||
glm::vec3 position;
|
||||
glm::vec3 color;
|
||||
float attenuation;
|
||||
glm::vec3 position = glm::vec3(0, 0, 0);
|
||||
glm::vec3 color = glm::vec3(1, 1, 1);
|
||||
float attenuation = 1;
|
||||
};
|
||||
|
||||
struct DirectionalLight
|
||||
{
|
||||
glm::vec3 direction;
|
||||
glm::vec3 color;
|
||||
glm::vec3 direction = glm::vec3(0, 1, 0);
|
||||
glm::vec3 color = glm::vec3(1, 1, 1);
|
||||
};
|
||||
|
||||
class Scene
|
||||
{
|
||||
public:
|
||||
void addPointLight(PointLight point) { points.push_back(point); }
|
||||
void addPointLight(PointLight point) { pointLights.push_back(point); }
|
||||
void addDirectionalLight(DirectionalLight dir) { directionalLights.push_back(dir); }
|
||||
void addModel(PModel model, glm::mat4 transform);
|
||||
void addModels(std::vector<PModel> models, glm::mat4 transform);
|
||||
void generate();
|
||||
|
||||
std::optional<IntersectionInfo> traceRay(Ray ray) const;
|
||||
void traceRay(Ray ray, Payload& payload, const float tmin, const float tmax) const noexcept;
|
||||
|
||||
private:
|
||||
std::vector<glm::vec3> positionPool;
|
||||
@@ -44,7 +44,7 @@ private:
|
||||
std::vector<glm::vec3> edgesPool;
|
||||
std::vector<glm::vec3> faceNormalsPool;
|
||||
|
||||
std::vector<PointLight> points;
|
||||
std::vector<PointLight> pointLights;
|
||||
std::vector<DirectionalLight> directionalLights;
|
||||
|
||||
DECLARE_REF(Node)
|
||||
@@ -60,6 +60,9 @@ private:
|
||||
PNode hierarchy;
|
||||
std::vector<PModel> models;
|
||||
|
||||
std::vector<IntersectionInfo> generateIntersections(const PNode& currentNode, Ray ray) const;
|
||||
std::optional<IntersectionInfo> intersectModel(const ModelReference& reference, Ray ray) const;
|
||||
// tests if a ray intersects any geometry, no hit information, for shadow rays
|
||||
bool testIntersection(const PNode& currentNode, const Ray ray, const float tmin, const float tmax) const noexcept;
|
||||
std::vector<IntersectionInfo> generateIntersections(const PNode& currentNode, const Ray ray, const float tmin, const float tmax) const noexcept;
|
||||
bool testModel(const ModelReference& reference, const Ray ray, const float tmin, const float tmax) const noexcept;
|
||||
std::vector<IntersectionInfo> intersectModel(const ModelReference& reference, const Ray ray, const float tmin, const float tmax) const noexcept;
|
||||
};
|
||||
+4
-2
@@ -1,11 +1,13 @@
|
||||
#include "BRDF.h"
|
||||
#include "Model.h"
|
||||
|
||||
glm::vec3 BlinnPhong::evaluate(HitInfo hit, glm::vec3 viewDir, glm::vec3 lightDir, glm::vec3 lightColor)
|
||||
glm::vec3 BRDF::evaluate(HitInfo hit, glm::vec3 viewDir, glm::vec3 lightDir, glm::vec3 lightColor)
|
||||
{
|
||||
// todo: switch for materialtype, this is blinnphong
|
||||
glm::vec3 normal = hit.normal;
|
||||
float diffuse = std::max(glm::dot(normal, lightDir), 0.0f);
|
||||
glm::vec3 h = glm::normalize(lightDir + viewDir);
|
||||
float specular = pow(std::min(std::max(glm::dot(normal, h), 0.0f), 1.0f), shininess);
|
||||
|
||||
return (albedo * diffuse * lightColor) + (specularColor * specular);
|
||||
}
|
||||
}
|
||||
|
||||
+6
-5
@@ -1,17 +1,18 @@
|
||||
#pragma once
|
||||
#include "Material.h"
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
class BRDF
|
||||
enum class MaterialType
|
||||
{
|
||||
virtual glm::vec3 evaluate(HitInfo hit, glm::vec3 viewDir, glm::vec3 lightDir, glm::vec3 lightColor) = 0;
|
||||
BlinnPhong
|
||||
};
|
||||
|
||||
class BlinnPhong : public BRDF
|
||||
struct BRDF
|
||||
{
|
||||
glm::vec3 albedo = glm::vec3(1, 1, 1);
|
||||
float alpha = 1;
|
||||
glm::vec3 specularColor = glm::vec3(1, 1, 1);
|
||||
float shininess = 0;
|
||||
glm::vec3 emissive = glm::vec3(0, 0, 0);
|
||||
virtual glm::vec3 evaluate(HitInfo hit, glm::vec3 viewDir, glm::vec3 lightDir, glm::vec3 lightColor);
|
||||
MaterialType materialType;
|
||||
glm::vec3 evaluate(struct HitInfo hit, glm::vec3 viewDir, glm::vec3 lightDir, glm::vec3 lightColor);
|
||||
};
|
||||
@@ -1,6 +1,12 @@
|
||||
#include "Material.h"
|
||||
#include "BRDF.h"
|
||||
|
||||
std::unique_ptr<BRDF> Material::evaluate(HitInfo hitInfo)
|
||||
BRDF Material::evaluate(HitInfo hitInfo)
|
||||
{
|
||||
return std::make_unique<BlinnPhong>();
|
||||
return BRDF{
|
||||
.albedo = glm::vec3(hitInfo.texCoords, 0),
|
||||
.alpha = 1,
|
||||
.emissive = glm::vec3(0, 0, 0),
|
||||
.materialType = MaterialType::BlinnPhong,
|
||||
};
|
||||
}
|
||||
|
||||
+1
-8
@@ -4,17 +4,10 @@
|
||||
#include "Ray.h"
|
||||
#include "BRDF.h"
|
||||
|
||||
enum class MaterialType
|
||||
{
|
||||
DIFFUSE,
|
||||
SPECULAR,
|
||||
REFRACTIVE,
|
||||
};
|
||||
|
||||
class Material
|
||||
{
|
||||
public:
|
||||
std::unique_ptr<BRDF> evaluate(HitInfo hitInfo);
|
||||
BRDF evaluate(HitInfo hitInfo);
|
||||
PTexture albedoTexture;
|
||||
PTexture emissiveTexture;
|
||||
};
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
struct IntersectionInfo
|
||||
{
|
||||
HitInfo hitInfo;
|
||||
MaterialInfo shadingInfo;
|
||||
BRDF brdf;
|
||||
};
|
||||
class Model
|
||||
{
|
||||
|
||||
+6
-3
@@ -4,15 +4,15 @@
|
||||
struct Payload
|
||||
{
|
||||
glm::vec3 accumulatedRadiance = glm::vec3(0);
|
||||
glm::vec3 accumulatedMaterial = glm::vec3(0);
|
||||
glm::vec3 accumulatedMaterial = glm::vec3(1);
|
||||
uint32_t depth = 0;
|
||||
float emissive = 1;
|
||||
};
|
||||
|
||||
struct Ray
|
||||
{
|
||||
glm::vec3 origin;
|
||||
glm::vec3 direction;
|
||||
uint32_t depth = 0;
|
||||
Payload payload;
|
||||
};
|
||||
|
||||
struct HitInfo
|
||||
@@ -20,5 +20,8 @@ struct HitInfo
|
||||
float t;
|
||||
glm::vec3 position;
|
||||
glm::vec3 normal;
|
||||
// not entirely sure what that does
|
||||
// its the normal being flipped based on some dot product
|
||||
glm::vec3 normalLight;
|
||||
glm::vec2 texCoords;
|
||||
};
|
||||
@@ -51,7 +51,7 @@ Window::Window(int width, int height) : width(width), height(height)
|
||||
|
||||
uniform sampler2D tex;
|
||||
|
||||
void main() { color = texture(tex, texcoords); });
|
||||
void main() { color = texture(tex, vec2(texcoords.x, -texcoords.y)); });
|
||||
glShaderSource(vertShader, 1, &vertCode, nullptr);
|
||||
glCompileShader(vertShader);
|
||||
int success;
|
||||
|
||||
@@ -20,6 +20,5 @@ class Window
|
||||
GLuint program;
|
||||
GLuint vertShader;
|
||||
GLuint fragShader;
|
||||
GLuint textureLocation;
|
||||
GLFWwindow* window;
|
||||
};
|
||||
Reference in New Issue
Block a user