asteroidgen/src/TextureMapper.cpp

222 lines
7.4 KiB
C++

#include "TextureMapper.h"
#include <glm/mat3x3.hpp>
#include "stb_image_write.h"
#include <iostream>
TextureMapper::TextureMapper(Density &density, size_t textureSize) :
density(density), textureSize(textureSize), albedo(
textureSize * textureSize), normal(textureSize * textureSize), roughness(
textureSize * textureSize), darkestColor(0.3, 0.25, 0.2, 1.0), brightestColor(
0.9, 0.85, 0.8, 1.0) {
}
void TextureMapper::setTextureSize(size_t size) {
textureSize = size;
albedo.resize(textureSize * textureSize);
normal.resize(textureSize * textureSize);
roughness.resize(textureSize * textureSize);
}
size_t TextureMapper::getTextureSize() {
return textureSize;
}
void TextureMapper::map(const vec3v_t &inVertices, const vec3v_t &inNormals,
const uvec3v_t &inIndices) {
float texf = 1. / textureSize;
vertices.clear();
vertices.reserve(inIndices.size() * 3);
normals.clear();
normals.reserve(inIndices.size() * 3);
texcoords.clear();
texcoords.reserve(inIndices.size() * 3);
// 2 px margin
size_t marginPixels = 2;
float margin = marginPixels * texf;
std::fill(albedo.begin(), albedo.end(), 255.f * brightestColor);
std::fill(normal.begin(), normal.end(), ucvec4_t(255, 255, 255, 255));
std::fill(roughness.begin(), roughness.end(), 255);
int rects = ceil(sqrt(inIndices.size())), rx = 0, ry = 0;
float rectSizePixel = floor(((float)textureSize - (rects + 1) * marginPixels) / rects);
float rectSize = rectSizePixel / textureSize;
printf("Rects: %d, Size: %f", rects, rectSize);
for (size_t i = 0; i < inIndices.size(); i++) {
glm::vec3 p[3], n[3];
glm::uvec3 idx = inIndices[i];
indices.push_back(
glm::uvec3(vertices.size(), vertices.size() + 1,
vertices.size() + 2));
for (size_t j = 0; j < 3; j++) {
p[j] = inVertices[idx[j]];
vertices.push_back(p[j]);
n[j] = inNormals[idx[j]];
normals.push_back(n[j]);
}
glm::vec3 ex = glm::normalize(p[1] - p[0]);
glm::vec3 ey = glm::normalize(glm::cross(ex, p[2] - p[0]));
glm::vec3 ez = glm::normalize(glm::cross(ex, ey));
glm::mat3 base = glm::mat3(ex, ey, ez);
glm::vec3 t[3] = { p[0] * base, p[1] * base, p[2] * base };
glm::vec3 lower = min(min(t[0], t[1]), t[2]);
glm::vec3 upper = max(max(t[0], t[1]), t[2]);
t[0] -= lower;
t[1] -= lower;
t[2] -= lower;
glm::vec3 extent = upper - lower;
float s = std::max(std::max(extent.x, extent.y), extent.z);
t[0] *= 0.9 * rectSize / s;
t[1] *= rectSize / s;
t[2] *= rectSize / s;
glm::vec3 off(margin + rx * (rectSize + margin), 0, margin + ry * (rectSize + margin));
t[0] += off;
t[1] += off;
t[2] += off;
texcoords.push_back(glm::vec2(t[0].x, t[0].z));
texcoords.push_back(glm::vec2(t[1].x, t[1].z));
texcoords.push_back(glm::vec2(t[2].x, t[2].z));
#if 0
//if (rx == 0 && ry == 0) {
t[0].y = 0;
t[1].y = 0;
t[2].y = 0;
// cout << "ftex " << texf << endl;
// cout << "t[0] " << t[0].x << " " << t[0].z << endl;
// cout << "t[1] " << t[1].x << " " << t[1].z << endl;
// cout << "t[2] " << t[2].x << " " << t[2].z << endl;
// cout << "t[0]p " << t[0].x * ntex << " " << (1 - t[0].z) * ntex << endl;
// cout << "t[1]p " << t[1].x * ntex << " " << (1 - t[1].z) * ntex << endl;
// cout << "t[2]p " << t[2].x * ntex << " " << (1 - t[2].z) * ntex << endl;
// fill texture
// fill whole rect for now
int rpix = floor(rectSize * textureSize);
glm::vec3 eb = t[1] - t[0];
float leb = glm::length(eb);
glm::vec3 ec = t[2] - t[0];
float lec = glm::length(ec);
// mat2 textureBase = mat2(vec2(eb.x, eb.z), vec2(ec.x, ec.z));
// mat2 itextureBase = inverse(textureBase);
glm::mat3 textureBase = glm::mat3(eb, glm::cross(eb, ec), ec);
glm::mat3 itextureBase = glm::inverse(textureBase);
// eb = normalize(eb);
// ec = normalize(ec);
glm::vec3 db = p[1] - p[0];
glm::vec3 dc = p[2] - p[0];
glm::vec3 mb = glm::normalize(p[1] - p[0]);
glm::vec3 mc = glm::normalize(p[2] - p[0]);
// mat2 faceBase = mat2(vec2(mb.x, mb.z), vec2(mc.x, mc.z));
// mat2 ifaceBase = inverse(faceBase);
glm::mat3 faceBase = glm::mat3(db, glm::cross(db, dc), dc);
glm::mat3 ifaceBase = glm::inverse(faceBase);
glm::vec3 tmin = min(min(t[0], t[1]), t[2]);
tmin = tmin * glm::vec3((float) textureSize);
tmin = floor(tmin) - glm::vec3(2.0f);
//tmin = tmin - glm::vec3(1.0f);
tmin = max(tmin, glm::vec3(0.1));
// glm::vec3 tmax = min(
// ceil(
// max(max(t[0], t[1]), t[2])
// * glm::vec3((float) textureSize))
// + glm::vec3(1.0f), glm::vec3(textureSize - 1));
glm::vec3 tmax = max(max(t[0], t[1]), t[2]);
tmax = tmax * glm::vec3((float) textureSize);
tmax = ceil(tmax) + glm::vec3(2.0f);
tmax = min(tmax, glm::vec3(textureSize));
// TODO: borders!
for (int ix = tmin.x; ix < tmax.x; ix++) {
for (int iy = (textureSize - tmax.z); iy < (textureSize - tmin.z);
iy++) {
// https://stackoverflow.com/questions/2049582/how-to-determine-if-a-point-is-in-a-2d-triangle#2049593
// for (int iy = tmin.z; iy < tmax.z; iy++) {
// cout << "pix " << ix << " " << iy << endl;
// cout << "uv " << float(ix) * texf << " " << 1.f - float(iy) * texf << endl;
// pixel to uv space
glm::vec3 res = glm::vec3(float(ix) * texf, 0.f,
1.f - float(iy) * texf) - t[0];
// cout << "r = " << r.x << " " << r.y << endl;
glm::vec3 local = faceBase * itextureBase * res;
// cout << "res = " << res.x << " " << res.y << endl;
// vec2 res = ifaceBase * textureBase * r * faceBase;
//
// cout << "pix " << ix << " " << res.x << " " << res.y << " " << res.z << endl;
// float fb = dot(r, eb) / leb;
// float fc = dot(r, ec) / lec;
glm::vec3 sp = p[0] + local; //res.x * mb + res.y * mc;
float v = (float) density(sp, false);
//
//v = pow(v, 3);
// default color
// float r = 0.8 + v * 0.2, g = 0.75 + 0.2 * v, b = 0.7
// + 0.2 * v;
glm::vec3 rgb = glm::vec3(255)
* glm::mix(darkestColor, brightestColor, v);
albedo[ix + (textureSize - iy) * textureSize][0] = rgb.x;
albedo[ix + (textureSize - iy) * textureSize][1] = rgb.y;
albedo[ix + (textureSize - iy) * textureSize][2] = rgb.z;
// diff[ix + iy * ntex] = v * 255;
// diff[ix + iy * ntex][0] = (32 * rx) % 255;
// diff[ix + iy * ntex][1] = (32 * ry) % 255;
// diff[ix + iy * ntex][2] = 0; //(0.5 + sp.z) * 255;
// float rd = 1.f; //0.7 + 0.3 * length(r) * rects;
// albedo[ix + (textureSize - iy) * textureSize][0] = rd * (sp.x) * 255;
// albedo[ix + (textureSize - iy) * textureSize][1] = rd * (sp.y) * 255;
// albedo[ix + (textureSize - iy) * textureSize][2] = rd * (sp.z) * 255;
// albedo[ix + iy * textureSize][0] = length(res) * rects * 255;
// albedo[ix + iy * textureSize][1] = length(res) * rects * 255;
// albedo[ix + iy * textureSize][2] = length(res) * rects * 255;
// diff[ix + iy * ntex][0] = r.x * rects * 200;
// diff[ix + iy * ntex][1] = -r.z * rects * 200;
// diff[ix + iy * ntex][2] = 0;
// diff[ix + iy * ntex][0] = 128 + (res.x - 0.5) * 200;
// diff[ix + iy * ntex][1] = 128 + (res.y - 0.5) * 200;
// diff[ix + iy * ntex][2] = 0; //res.z * 255;
}
//}
}
rx++;
if (rx >= rects) {
rx = 0;
ry++;
}
#endif
}
//
// for (int ix = 0; ix < ntex; ix++) {
// for (int iy = 0; iy < ntex; iy++) {
//
// float v = (float) noise.octaveNoise0_1(ix * texf * frequency,
// iy * texf * frequency, 0.5 * frequency, 4);
// diff[ix + (ntex - iy) * ntex] = 5 + v * 250;
// }
// }
stbi_write_png("albedo.png", textureSize, textureSize, 3, albedo.data(), 0);
}