【开发日志】2023.05 ZENO----ApplyNormalMap----法线贴图、纹理映射

法线贴图

NormalMap-Online (cpetry.github.io)https://cpetry.github.io/NormalMap-Online/

(4条消息) 【开发日志】2023.04 ZENO----Composite----CompNormalMap_EndlessDaydream的博客-CSDN博客https://blog.csdn.net/Angelloveyatou/article/details/130319455


#include <iostream>
#include <cmath>

// 结构体表示顶点
struct Vertex {
    float position[3];
    float normal[3];
};

// 函数用于将法线贴图应用到正方体的顶点上
void ApplyNormalMap(Vertex* vertices, int numVertices, float* normalMap, int width, int height) {
    for (int i = 0; i < numVertices; ++i) {
        float u = vertices[i].position[0];  // 顶点的x坐标作为法线贴图的u坐标
        float v = vertices[i].position[1];  // 顶点的y坐标作为法线贴图的v坐标

        int x = std::round(u * (width - 1));   // 根据坐标计算法线贴图中的像素位置
        int y = std::round(v * (height - 1));

        // 从法线贴图中获取法线向量
        float nx = normalMap[(y * width + x) * 3];
        float ny = normalMap[(y * width + x) * 3 + 1];
        float nz = normalMap[(y * width + x) * 3 + 2];

        // 归一化法线向量
        float length = std::sqrt(nx * nx + ny * ny + nz * nz);
        nx /= length;
        ny /= length;
        nz /= length;

        // 更新顶点的法线属性
        vertices[i].normal[0] = nx;
        vertices[i].normal[1] = ny;
        vertices[i].normal[2] = nz;
    }
}

 

 

 


纹理映射

struct CreateSphere : zeno::INode {
    virtual void apply() override {
        auto prim = std::make_shared<zeno::PrimitiveObject>();
        auto position = get_input2<zeno::vec3f>("position");
        auto scale = get_input2<zeno::vec3f>("scaleSize");
        auto rows = get_input2<int>("rows");
        auto columns = get_input2<int>("columns");
        auto radius = get_input2<float>("radius");
        auto quad = get_input2<bool>("quads");

        if (rows < 2) {
            rows = 2;
        }
        if (columns < 3) {
            columns = 3;
        }
        std::vector<zeno::vec3f> verts = {};
        std::vector<zeno::vec2i> poly = {};
        std::vector<int> loops = {};
        std::vector<zeno::vec2f> uvs = {};
        std::vector<zeno::vec3f> nors = {};

        verts.push_back (vec3f(0,1,0));
        for (auto row = 1; row < rows; row++) {
            float v = (float)row / (float)rows;
            float theta = M_PI * v;
            for (auto column = 0; column < columns; column++) {
                float u = (float)column / (float)columns;
                float phi = M_PI * 2 * u;
                float x = sin(theta) * cos(phi);
                float y = cos(theta);
                float z = -sin(theta) * sin(phi);
                verts.push_back(vec3f(x,y,z));
            }
        }
        verts.push_back (vec3f(0,-1,0));
        {
            //head
            for (auto column = 0; column < columns; column++) {
                if (column == columns - 1) {
                    loops.push_back(0);
                    loops.push_back(columns);
                    loops.push_back(1);
                    poly.push_back(vec2i(column * 3, 3));
                } else {
                    loops.push_back(0);
                    loops.push_back(column + 1);
                    loops.push_back(column + 2);
                    poly.push_back(vec2i(column * 3, 3));
                }
            }
            //body
            for (auto row = 1; row < rows - 1; row++) {
                for (auto column = 0; column < columns; column++) {
                    if (column == columns - 1) {
                        loops.push_back((row - 1) * columns + 1);
                        loops.push_back((row - 1) * columns + columns);
                        loops.push_back(row * columns + columns);
                        loops.push_back(row * columns + 1);
                        poly.push_back(vec2i(columns * 3 + (row - 1) * columns * 4 + column * 4, 4));
                    } else {
                        loops.push_back((row - 1) * columns + column + 2);
                        loops.push_back((row - 1) * columns + column + 1);
                        loops.push_back(row * columns + column + 1);
                        loops.push_back(row * columns + column + 2);
                        poly.push_back(vec2i(loops.size() - 4, 4));
                    }
                }
            }
            //tail
            for (auto column = 0; column < columns; column++) {
                if (column == columns - 1) {
                    loops.push_back((rows - 2) * columns + 1);
                    loops.push_back((rows - 2) * columns + column + 1);
                    loops.push_back((rows - 1) * columns + 1);
                    poly.push_back(vec2i(columns * 3 + (rows - 2) * columns * 4 + column * 3, 3));
                } else {
                    loops.push_back((rows - 2) * columns + column + 2);
                    loops.push_back((rows - 2) * columns + column + 1);
                    loops.push_back((rows - 1) * columns + 1);
                    poly.push_back(vec2i(loops.size() - 3, 3));
                }
            }
        }

        for(int column = 0;column < columns;column++){
            uvs.push_back({(column+0.5f)/columns, 1.0f, 0.0f});
        }
        for(int row = 1;row < rows;row++){
            for(int column = 0;column < columns+1;column++){
                uvs.push_back({(column+0.0f)/columns,1.0f-(row+0.0f)/rows,0.0f});
            }
        }
        for(int column = 0;column < columns;column++){
            uvs.push_back({(column+0.5f)/columns, 0.0f, 0.0f});
        }

        auto& loops_uv = prim->loops.add_attr<int>("uvs");
        loops_uv.resize(0);
        for(int column = 0;column < columns;column++){
            loops_uv.push_back(column);
            loops_uv.push_back(columns+column);
            loops_uv.push_back(columns+column+1);
        }
        for(int row = 1;row < rows-1;row++){
            for(int column = 0;column < columns;column++){
                loops_uv.push_back(columns+(columns+1)*(row-1)+column+1);
                loops_uv.push_back(columns+(columns+1)*(row-1)+column);
                loops_uv.push_back(columns+(columns+1)*row+column);
                loops_uv.push_back(columns+(columns+1)*row+column+1);
            }
        }
        for(int column = 0;column < columns;column++){
            loops_uv.push_back(columns+(columns+1)*(rows-2)+column+1);
            loops_uv.push_back(columns+(columns+1)*(rows-2)+column);
            loops_uv.push_back(columns+(columns+1)*(rows-1)+column);
        }

        nors.resize(verts.size());
        for(int i = 0; i < verts.size(); i++){
            auto n = verts[i];
            auto p = verts[i];
            auto rotate = get_input2<zeno::vec3f>("rotate");
            glm::mat4 transform = glm::mat4 (1.0);
            transform = glm::translate(transform, glm::vec3(position[0], position[1], position[2]));
            transform = glm::rotate(transform, glm::radians(rotate[0]), glm::vec3(1, 0, 0));
            transform = glm::rotate(transform, glm::radians(rotate[1]), glm::vec3(0, 1, 0));
            transform = glm::rotate(transform, glm::radians(rotate[2]), glm::vec3(0, 0, 1));
            transform = glm::scale(transform, glm::vec3(scale[0],scale[1],scale[2]) * radius);
            auto gp = transform * glm::vec4(p[0], p[1], p[2], 1);
            verts[i] = zeno::vec3f(gp.x, gp.y, gp.z);

            auto n_transform = glm::transpose(glm::inverse(transform));
            auto gn = n_transform * glm::vec4 (n[0], n[1], n[2], 0);
            nors[i] = zeno::vec3f (gn.x, gn.y, gn.z);
        }

        prim->verts.resize(verts.size());
        for (auto i = 0; i < verts.size(); i++) {
            prim->verts[i] = verts[i];
        }
        prim->polys.resize(poly.size());
        for (auto i = 0; i < poly.size(); i++) {
            prim->polys[i] = poly[i];
        }
        prim->loops.resize(loops.size());
        for (auto i = 0; i < loops.size(); i++) {
            prim->loops[i] = loops[i];
        }
        prim->uvs.resize(uvs.size());

        for (auto i = 0; i < uvs.size(); i++) {
            prim->uvs[i] = uvs[i];
        }

        auto &nors2 = prim->verts.add_attr<zeno::vec3f>("nrm");
        for (auto i = 0; i < nors.size(); i++) {
            nors2[i] = nors[i];
        }

        if (!get_input2<bool>("hasNormal")){
            prim->verts.attrs.erase("nrm");
        }

        if (!get_input2<bool>("hasVertUV")){
            prim->uvs.clear();
            prim->loops.erase_attr("uvs");
        }

        if (get_input2<bool>("isFlipFace")){
            for (auto i = 0; i < prim->polys.size(); i++) {
                auto [base, cnt] = prim->polys[i];
                for (int j = 0; j < (cnt / 2); j++) {
                    std::swap(prim->loops[base + j], prim->loops[base + cnt - 1 - j]);
                    if (prim->loops.has_attr("uvs")) {
                        std::swap(prim->loops.attr<int>("uvs")[base + j], prim->loops.attr<int>("uvs")[base + cnt - 1 - j]);
                    }
                }
            }
        }

        if(!quad){
            primTriangulate(prim.get());
        }
        set_output("prim",std::move(prim));
    }
};

ZENDEFNODE(CreateSphere, {
    {
        {"vec3f", "position", "0, 0, 0"},
        {"vec3f", "scaleSize", "1, 1, 1"},
        {"float", "radius", "1"},
        ROTATE_PARM
        NORMUV_PARM
        {"int", "rows", "12"},
        {"int", "columns", "24"},
        {"bool", "quads", "0"},
    },
    {"prim"},
    {},
    {"create"},
});
struct PrimUVEdgeDuplicate : INode {
    virtual void apply() override {
        auto prim = get_input<PrimitiveObject>("prim");
        auto writeUVToVertex = get_input2<bool>("writeUVToVertex");
        bool isTris = prim->tris.size() > 0;
        if (isTris) {
            primPolygonate(prim.get(), true);
        }
        std::map<std::tuple<int, int>, int> mapping;
        std::vector<std::pair<int, int>> new_vertex_index;
        std::vector<int> new_loops;
        auto& uvs = prim->loops.attr<int>("uvs");
        for (auto i = 0; i < prim->loops.size(); i++) {
            int vi = prim->loops[i];
            int uvi = uvs[i];
            if (mapping.count({vi, uvi}) == 0) {
                int index = mapping.size();
                mapping[{vi, uvi}] = index;
                new_vertex_index.emplace_back(vi, uvi);
            }
            new_loops.push_back(mapping[{vi, uvi}]);
        }
        for (auto i = 0; i < prim->loops.size(); i++) {
            prim->loops[i] = new_loops[i];
        }

        AttrVector<vec3f> new_verts;
        new_verts.resize(mapping.size());
        for (auto i = 0; i < mapping.size(); i++) {
            int org = new_vertex_index[i].first;
            new_verts[i] = prim->verts[org];
        }
        prim->verts.foreach_attr<AttrAcceptAll>([&] (auto const &key, auto const &arr) {
            using T = std::decay_t<decltype(arr[0])>;
            auto &attr = new_verts.add_attr<T>(key);
            for (auto i = 0; i < attr.size(); i++) {
                attr[i] = arr[new_vertex_index[i].first];
            }
        });
        std::swap(prim->verts, new_verts);
        if (writeUVToVertex) {
            auto &vert_uv = prim->verts.add_attr<vec3f>("uv");
            auto &loopsuv = prim->loops.attr<int>("uvs");
            for (auto i = 0; i < prim->loops.size(); i++) {
                auto uv = prim->uvs[loopsuv[i]];
                vert_uv[prim->loops[i]] = {uv[0], uv[1], 0};
            }
        }
        if (isTris) {
            primTriangulate(prim.get(), true, false);
        }

        set_output("prim", std::move(prim));
    }
};

ZENO_DEFNODE(PrimUVEdgeDuplicate)({
     {
         "prim",
         {"bool", "writeUVToVertex", "1"},
     },
     {
         "prim",
     },
     {},
     {"primitive"},
 });
void primSampleTexture(
    std::shared_ptr<PrimitiveObject> prim,
    const std::string &srcChannel,
    const std::string &uvSource,
    const std::string &dstChannel,
    std::shared_ptr<PrimitiveObject> img,
    const std::string &wrap,
    const std::string &filter,
    vec3f borderColor,
    float remapMin,
    float remapMax
) {
    if (!img->userData().has("isImage")) throw zeno::Exception("not an image");
    using ColorT = float;
    const ColorT *data = (float *)img->verts.data();
    auto &clr = prim->add_attr<zeno::vec3f>(dstChannel);
    auto w = img->userData().get2<int>("w");
    auto h = img->userData().get2<int>("h");
    std::function<zeno::vec3f(vec3f, const ColorT*, int, int, int, vec3f)> queryColor;
    if (filter == "nearest") {
        if (wrap == "REPEAT") {
            queryColor = [=](vec3f uv, const ColorT *data, int w, int h, int n, vec3f _clr) -> vec3f {
                uv = (uv - remapMin) / (remapMax - remapMin);
                auto iuv = uvRepeat(uv, w, h);
                return queryColorInner(iuv, data, w, n);
            };
        } else if (wrap == "CLAMP_TO_EDGE") {
            queryColor = [=](vec3f uv, const ColorT *data, int w, int h, int n, vec3f _clr) -> vec3f {
                uv = (uv - remapMin) / (remapMax - remapMin);
                auto iuv = uvClampToEdge(uv, w, h);
                return queryColorInner(iuv, data, w, n);
            };
        } else if (wrap == "CLAMP_TO_BORDER") {
            queryColor = [=](vec3f uv, const ColorT *data, int w, int h, int n, vec3f clr) -> vec3f {
                uv = (uv - remapMin) / (remapMax - remapMin);
                if (uv[0] < 0 || uv[0] > 1 || uv[1] < 0 || uv[1] > 1) {
                    return clr;
                }
                auto iuv = uvClampToEdge(uv, w, h);
                return queryColorInner(iuv, data, w, n);
            };
        } else {
            zeno::log_error("wrap type error");
            throw std::runtime_error("wrap type error");
        }
    }
    else {
        queryColor = [=](vec3f uv, const ColorT *data, int w, int h, int n, vec3f _clr) -> vec3f {
            uv = (uv - remapMin) / (remapMax - remapMin);
            float u, v;
            auto iuv = uvClampToEdge(uv, w, h, u, v);

            auto c00 = queryColorInner(iuv, data, w, n, h);
            auto c01 = queryColorInner(iuv + vec2i(1, 0), data, w, n, h);
            auto c10 = queryColorInner(iuv + vec2i(0, 1), data, w, n, h);
            auto c11 = queryColorInner(iuv + vec2i(1, 1), data, w, n, h);
            auto a = zeno::mix(c00, c01, u);
            auto b = zeno::mix(c10, c11, u);
            auto c = zeno::mix(a, b, v);
            return c;
        };
    }

    if (uvSource == "vertex") {
        auto &uv = prim->attr<zeno::vec3f>(srcChannel);
        #pragma omp parallel for
        for (auto i = 0; i < uv.size(); i++) {
            clr[i] = queryColor(uv[i], data, w, h, 3, borderColor);
        }
    }
    else if (uvSource == "tris") {
        auto uv0 = prim->tris.attr<vec3f>("uv0");
        auto uv1 = prim->tris.attr<vec3f>("uv1");
        auto uv2 = prim->tris.attr<vec3f>("uv2");
        #pragma omp parallel for
        for (auto i = 0; i < prim->tris.size(); i++) {
            auto tri = prim->tris[i];
            clr[tri[0]] = queryColor(uv0[i], data, w, h, 3, borderColor);
            clr[tri[1]] = queryColor(uv1[i], data, w, h, 3, borderColor);
            clr[tri[2]] = queryColor(uv2[i], data, w, h, 3, borderColor);
        }

    }
    else if (uvSource == "loopsuv") {
        auto &loopsuv = prim->loops.attr<int>("uvs");
        #pragma omp parallel for
        for (auto i = 0; i < prim->loops.size(); i++) {
            auto uv = prim->uvs[loopsuv[i]];
            int index = prim->loops[i];
            clr[index] = queryColor({uv[0], uv[1], 0}, data, w, h, 3, borderColor);
        }
    }
    else {
        zeno::log_error("unknown uvSource");
        throw std::runtime_error("unknown uvSource");
    }
}

void primSampleTexture(
        std::shared_ptr<PrimitiveObject> prim,
        const std::string &srcChannel,
        const std::string &uvSource,
        const std::string &dstChannel,
        std::shared_ptr<PrimitiveObject> img,
        const std::string &wrap,
        vec3f borderColor,
        float remapMin,
        float remapMax
) {
    return primSampleTexture(prim, srcChannel, uvSource, dstChannel, img, wrap, "nearest", borderColor, remapMin, remapMax);;
}
struct PrimSample2D : zeno::INode {
    virtual void apply() override {
        auto prim = get_input<PrimitiveObject>("prim");
        auto srcChannel = get_input2<std::string>("uvChannel");
        auto srcSource = get_input2<std::string>("uvSource");
        auto dstChannel = get_input2<std::string>("targetChannel");
        auto image = get_input2<PrimitiveObject>("image");
        auto wrap = get_input2<std::string>("wrap");
        auto filter = get_input2<std::string>("filter");
        auto borderColor = get_input2<vec3f>("borderColor");
        auto remapMin = get_input2<float>("remapMin");
        auto remapMax = get_input2<float>("remapMax");
        primSampleTexture(prim, srcChannel, srcSource, dstChannel, image, wrap, filter, borderColor, remapMin, remapMax);

        set_output("outPrim", std::move(prim));
    }
};
ZENDEFNODE(PrimSample2D, {
    {
        {"PrimitiveObject", "prim"},
        {"PrimitiveObject", "image"},
        {"string", "uvChannel", "uv"},
        {"enum vertex tris loopsuv", "uvSource", "vertex"},
        {"string", "targetChannel", "clr"},
        {"float", "remapMin", "0"},
        {"float", "remapMax", "1"},
        {"enum REPEAT CLAMP_TO_EDGE CLAMP_TO_BORDER", "wrap", "REPEAT"},
        {"enum nearest linear", "filter", "nearest"},
        {"vec3f", "borderColor", "0,0,0"},
    },
    {
        {"PrimitiveObject", "outPrim"}
    },
    {},
    {"primitive"},
});

Other Reference 

/*
 * Author: Christian Petry
 * Homepage: www.petry-christian.de
 *
 * License: MIT
 * Copyright (c) 2014 Christian Petry
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
 * and associated documentation files (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or 
 * substantial portions of the Software.
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 
 * OTHER DEALINGS IN THE SOFTWARE.
 */

//console.log("Warnings are disabled!");
//console.warn = function() {};

NMO_FileDrop.initHeightMap();
NMO_RenderView.initRenderer();

var NMO_Main = new function(){
	this.TextureEnum = {
	    NORMAL : 0,
	    DISPLACEMENT : 1,
	    AMBIENT : 2,
	    SPECULAR : 3
	}

	this.auto_update = true;
	this.current_texture = this.TextureEnum.NORMAL;
	this.normal_map_mode = "height";
	this.download_btn = document.getElementById('download');
	this.download_all_btn = document.getElementById('download_all');


	this.activate_height_tab = function(type){
		this.normal_map_mode = type;
		if (type == "height"){
			document.getElementById('tab_btn_heightmap').disabled = true;
			document.getElementById('tab_btn_pictures').disabled = false;
			$('#pictures_map').hide("slide", {direction: "right"}, 400, function() {
				NMO_RenderNormalview.reinitializeShader("height");
				NMO_RenderNormalview.renderNormalview_update("height");
				NMO_NormalMap.createNormalMap();
				NMO_Main.setTexturePreview(NMO_NormalMap.normal_canvas, "normal_img", NMO_NormalMap.normal_canvas.width, NMO_NormalMap.normal_canvas.height);
				NMO_DisplacementMap.createDisplacementMap();
				NMO_AmbientOccMap.createAmbientOcclusionTexture();
				NMO_SpecularMap.createSpecularTexture();
				$('#height_map').show("slide", {direction: "left"}, 400);
			});
		}
		else if (type == "pictures"){
			document.getElementById('tab_btn_pictures').disabled = true;
			document.getElementById('tab_btn_heightmap').disabled = false;
			$('#height_map').hide("slide", {direction: "left"}, 400, function() {
				NMO_RenderNormalview.reinitializeShader("pictures");
				NMO_RenderNormalview.renderNormalview_update("pictures");
				NMO_NormalMap.createNormalMap();
				NMO_Main.setTexturePreview(NMO_NormalMap.normal_canvas, "normal_img", NMO_NormalMap.normal_canvas.width, NMO_NormalMap.normal_canvas.height);
				NMO_RenderNormalview.renderNormalToHeight(); // when the last one was loaded
				NMO_DisplacementMap.createDisplacementMap();
				NMO_AmbientOccMap.createAmbientOcclusionTexture();
				NMO_SpecularMap.createSpecularTexture();
				$('#pictures_map').show("slide", {direction: "right"}, 400);
			});
		}
	}

	this.activate_texture = function(type){
		if (type == "normal"){
			document.getElementById('tab_btn_normal').disabled = true;
			document.getElementById('tab_btn_displace').disabled = false;
			document.getElementById('tab_btn_ao').disabled = false;
			document.getElementById('tab_btn_specular').disabled = false;
			//console.log("normal!");
			document.getElementById('normal_map').style.cssText = "";
			document.getElementById('normal_settings').style.cssText = "";
			
			document.getElementById('displacement_map').style.cssText = "display: none;";
			document.getElementById('displacement_settings').style.cssText = "display: none;";
			
			document.getElementById('ao_map').style.cssText = "display: none;";
			document.getElementById('ao_settings').style.cssText = "display: none;";

			document.getElementById('specular_map').style.cssText = "display: none;";
			document.getElementById('specular_settings').style.cssText = "display: none;";

			document.getElementById('file_name').placeholder = "NormalMap";
			this.current_texture = this.TextureEnum.NORMAL;
		}
		
		else if (type == "displace"){
			document.getElementById('tab_btn_normal').disabled = false;
			document.getElementById('tab_btn_displace').disabled = true;
			document.getElementById('tab_btn_ao').disabled = false;
			document.getElementById('tab_btn_specular').disabled = false;
			
			document.getElementById('normal_map').style.cssText = "display: none;";
			document.getElementById('normal_settings').style.cssText = "display: none;";
			
			document.getElementById('displacement_map').style.cssText = "";
			document.getElementById('displacement_settings').style.cssText = "";
			
			document.getElementById('ao_map').style.cssText = "display: none;";
			document.getElementById('ao_settings').style.cssText = "display: none;";

			document.getElementById('specular_map').style.cssText = "display: none;";
			document.getElementById('specular_settings').style.cssText = "display: none;";

			document.getElementById('file_name').placeholder = "DisplacementMap";
			this.current_texture = this.TextureEnum.DISPLACEMENT;
			//console.log("displace!");
		}
		else if (type == "ao"){
			document.getElementById('tab_btn_normal').disabled = false;
			document.getElementById('tab_btn_displace').disabled = false;
			document.getElementById('tab_btn_ao').disabled = true;
			document.getElementById('tab_btn_specular').disabled = false;
			
			document.getElementById('normal_map').style.cssText = "display: none;";
			document.getElementById('normal_settings').style.cssText = "display: none;";
			
			document.getElementById('displacement_map').style.cssText = "display: none;";
			document.getElementById('displacement_settings').style.cssText = "display: none;";
			
			document.getElementById('ao_map').style.cssText = "";
			document.getElementById('ao_settings').style.cssText = "";

			document.getElementById('specular_map').style.cssText = "display: none;";
			document.getElementById('specular_settings').style.cssText = "display: none;";

			document.getElementById('file_name').placeholder = "AmbientOcclusionMap";
			this.current_texture = this.TextureEnum.AMBIENT;
			//console.log("displace!");
		}
		else if (type == "specular"){
			document.getElementById('tab_btn_normal').disabled = false;
			document.getElementById('tab_btn_displace').disabled = false;
			document.getElementById('tab_btn_ao').disabled = false;
			document.getElementById('tab_btn_specular').disabled = true;
			
			document.getElementById('normal_map').style.cssText = "display: none;";
			document.getElementById('normal_settings').style.cssText = "display: none;";
			
			document.getElementById('displacement_map').style.cssText = "display: none;";
			document.getElementById('displacement_settings').style.cssText = "display: none;";

			document.getElementById('ao_map').style.cssText = "display: none;";
			document.getElementById('ao_settings').style.cssText = "display: none;";
			
			document.getElementById('specular_map').style.cssText = "";
			document.getElementById('specular_settings').style.cssText = "";

			document.getElementById('file_name').placeholder = "SpecularMap";
			this.current_texture = this.TextureEnum.SPECULAR;
			//console.log("displace!");
		}
	}


	this.setTexturePreview = function(canvas, img_id, width, height){
		var img = document.getElementById(img_id);

		//canvas.width = width;
		//canvas.height = height;

		//console.log(img_id + ": " + width);		

		img.getContext('2d').clearRect ( 0 , 0 , img.width, img.height );

			
		var ratio = width / height;
		var draw_width = ratio >= 1 ? NMO_FileDrop.container_height : (NMO_FileDrop.container_height * ratio );
		var draw_height = ratio >= 1 ? (NMO_FileDrop.container_height / ratio ) : NMO_FileDrop.container_height;
		
		var reduce_canvas = document.createElement('canvas');
		var helper_canvas = document.createElement('canvas');
		helper_canvas.width = width;
		helper_canvas.height = height;
		reduce_canvas.width = width;
		reduce_canvas.height = height;

		var current_width = width;
		var current_height = height;
		var reduce_context = reduce_canvas.getContext('2d');
		var helper_context = helper_canvas.getContext('2d');
		reduce_context.clearRect(0,0,reduce_context.width, reduce_context.height);
		reduce_context.drawImage(canvas, 0, 0, width, height);
		helper_context.clearRect(0,0,helper_canvas.width, helper_canvas.height);
		helper_context.drawImage(canvas, 0, 0, width, height);
		while(2*draw_width < current_width && 2*draw_height < current_height ){
			//console.log("redraw!");
			helper_context.clearRect(0, 0, helper_canvas.width, helper_canvas.height);
			helper_context.drawImage(reduce_canvas, 0, 0, reduce_canvas.width, reduce_canvas.height);
			reduce_context.clearRect(0, 0, reduce_canvas.width, reduce_canvas.height);
			reduce_context.drawImage(helper_canvas, 0, 0, reduce_canvas.width * 0.5, reduce_canvas.height * 0.5);
			current_width *= 0.5;
			current_height *= 0.5;
		}

		//console.log(draw_width + ", " + draw_height)
		img.height = draw_height;
		img.width = draw_width;
		img.getContext('2d').drawImage(reduce_canvas, 0, 0, current_width, current_height, 0,0, draw_width, draw_height);
		
		if (canvas == NMO_NormalMap.normal_canvas)
			NMO_RenderView.normal_map.needsUpdate = true;
		else if (canvas == NMO_DisplacementMap.displacement_canvas)
			NMO_RenderView.displacement_map.needsUpdate = true;
		else if (canvas == NMO_AmbientOccMap.ao_canvas)
			NMO_RenderView.ao_map.needsUpdate = true;
		else if (canvas == NMO_SpecularMap.specular_canvas)
			NMO_RenderView.specular_map.needsUpdate = true;
		
	}

	this.toggle_height_column = function(){

		if ($("#column_height").is(":visible") == true) {
			$("#column_btn_left_div").html("<<");
			$("#column_height").hide("slide", {direction: "right"}, 400);
				/*$(".column").each(function () {
	    		$(this).css("width", "438px");
				});
				$(".preview_img").each(function () {
		    		$(this).css("max-width", "400px");
		    		$(this).css("max-height", "400px");
				});
				$(".view").each(function () {
		    		$(this).css("max-width", "400px");
		    		$(this).css("max-height", "400px");
				});
				$(".helper").each(function () {
		    		$(this).css("max-width", "400px");
		    		$(this).css("max-height", "400px");
				});
				container_height = 400;
				updateCurrentTexture();
				renderer.setSize( 400, 400 );*/
		}
		else{
			$("#column_btn_left_div").html(">>");			
			$("#column_height").show("slide", {direction: "right"}, 400);
		}
	}

	this.toggle_preview_column = function(){

		if ($("#preview").is(":visible") == true) {
			$("#column_btn_right_div").html(">>");
			$("#preview").hide("slide", {direction: "left"}, 400);				
		}
		else{
			$("#column_btn_right_div").html("<<");
			$("#preview").show("slide", {direction: "left"}, 400);
		}
	}

	this.getImageType = function(){
		var select_file_type = document.getElementById('file_type');
		var file_type = select_file_type.options[select_file_type.selectedIndex].value;
		return file_type;
	};

	this.switchJPGQual = function(){
		if (this.getImageType() != 'jpg'){
			document.getElementById('file_jpg_qual').style.cssText = "display: none;";
			document.getElementById('total_transparency').style.cssText = "font-size:11px;";
		}
		else{
			document.getElementById('total_transparency').style.cssText = "display: none;";	
			document.getElementById('file_jpg_qual').style.cssText = "font-size:11px;";
		}
	};


	this.toggleAutoUpdate = function(){
		this.auto_update = !this.auto_update;
		
		if (this.auto_update)
			NMO_NormalMap.createNormalMap();
			NMO_DisplacementMap.createDisplacementMap();
			NMO_AmbientOccMap.createAmbientOcclusionTexture();
			NMO_SpecularMap.createSpecularTexture();
	};

	this.updateCurrentTexture = function(){
		if (this.current_texture == TextureEnum.NORMAL)
			NMO_NormalMap.createNormalMap();
		else if (this.current_texture == TextureEnum.DISPLACEMENT)
			NMO_DisplacementMap.createDisplacementMap();
		else if (this.current_texture == TextureEnum.AMBIENT)
			NMO_AmbientOccMap.createAmbientOcclusionTexture();
		else if (this.current_texture == TextureEnum.SPECULAR)
			NMO_SpecularMap.createSpecularTexture();
	};

	this.download_all_btn.addEventListener('click', function (e) {		
		NMO_Main.downloadImage("NormalMap");
		NMO_Main.downloadImage("DisplacementMap");
		NMO_Main.downloadImage("AmbientOcclusionMap");
		NMO_Main.downloadImage("SpecularMap");
	});
	
	this.download_btn.addEventListener('click', function (e) {		
		if (document.getElementById('normal_map').style.cssText != "display: none;"){
			NMO_Main.downloadImage("NormalMap");
		}
		else if (document.getElementById('displacement_map').style.cssText != "display: none;"){
			NMO_Main.downloadImage("DisplacementMap");
		}
		else if (document.getElementById('ao_map').style.cssText != "display: none;"){
			NMO_Main.downloadImage("AmbientOcclusionMap");
		}
		else if (document.getElementById('specular_map').style.cssText != "display: none;"){
			NMO_Main.downloadImage("SpecularMap");
		}		
	});
	
	
	this.downloadImage = function(type){
		console.log("Downloading image");
		var qual = 0.9;
		var file_name = "download";
		var canvas = document.createElement("canvas");
		
		var file_type = NMO_Main.getImageType();
		var image_type = "image/png";
		if (file_type == "jpg")
			image_type = "image/jpeg";

		if (type == "NormalMap"){
			canvas.width = NMO_NormalMap.normal_canvas.width;
			canvas.height = NMO_NormalMap.normal_canvas.height;
			var context = canvas.getContext('2d');
			if (file_type == "png") 
				context.globalAlpha = $('#transparency_nmb').val() / 100;
			context.drawImage(NMO_NormalMap.normal_canvas,0,0);
			file_name="NormalMap";
		}
		else if (type == "DisplacementMap"){
			canvas.width = NMO_DisplacementMap.displacement_canvas.width;
			canvas.height = NMO_DisplacementMap.displacement_canvas.height;
			var context = canvas.getContext('2d');
			if (file_type == "png") 
				context.globalAlpha = $('#transparency_nmb').val() / 100;
			context.drawImage(NMO_DisplacementMap.displacement_canvas,0,0);
			file_name="DisplacementMap";
		}
		else if (type == "AmbientOcclusionMap"){
			canvas.width = NMO_AmbientOccMap.ao_canvas.width;
			canvas.height = NMO_AmbientOccMap.ao_canvas.height;
			var context = canvas.getContext('2d');
			if (file_type == "png") 
				context.globalAlpha = $('#transparency_nmb').val() / 100;
			context.drawImage(NMO_AmbientOccMap.ao_canvas,0,0);
			file_name="AmbientOcclusionMap";
		}
		else if (type == "SpecularMap"){
			canvas.width = NMO_SpecularMap.specular_canvas.width;
			canvas.height = NMO_SpecularMap.specular_canvas.height;
			var context = canvas.getContext('2d');
			if (file_type == "png") 
				context.globalAlpha = $('#transparency_nmb').val() / 100;
			context.drawImage(NMO_SpecularMap.specular_canvas,0,0);
			file_name="SpecularMap";
		}
		
		if (document.getElementById('file_name').value != "")
			file_name = document.getElementById('file_name').value;
		
		
			
		var qual = $('#file_jpg_qual_nmb').val() / 100;
		if (file_type == "tiff"){
			CanvasToTIFF.toBlob(canvas, function(blob) {
   				saveAs(blob, file_name + ".tif");
		    });
		}
		else{
			canvas.toBlob(function(blob) {
	    		saveAs(blob, file_name + "." + file_type);
			}, image_type, qual);
		}
	}
}

/*
 * Author: Christian Petry
 * Homepage: www.petry-christian.de
 *
 * License: MIT
 * Copyright (c) 2014 Christian Petry
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
 * and associated documentation files (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or 
 * substantial portions of the Software.
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 
 * OTHER DEALINGS IN THE SOFTWARE.
 */

var NMO_NormalMap = new function(){

	this.invert_red = false;
	this.invert_green = false;
	this.invert_source = false;
	this.height_offset = true;
	this.smoothing = 0;
	this.strength = 2.5;
	this.level = 7;
	this.normal_type = "sobel";
	this.normal_canvas = document.createElement("canvas");

	this.getNextPowerOf2 = function(nmb){
		i = 2;
		while(i < Math.pow(2,14)){
			i *= 2;
			if(i >= nmb)
				return i;
		}
	};

	this.createNormalMap = function(){
		NMO_RenderNormalview.renderNormalView();
		NMO_Main.setTexturePreview(this.normal_canvas, "normal_img", this.normal_canvas.width, this.normal_canvas.height);
	};


	this.invertRed = function(){
		this.invert_red = !this.invert_red;
		if (this.invert_red){
			NMO_RenderNormalview.normalmap_uniforms["invertR"].value = -1;
			NMO_RenderNormalview.normalmap_from_pictures_uniforms["invertR"].value = -1;
		}
		else{
			NMO_RenderNormalview.normalmap_uniforms["invertR"].value = 1;
			NMO_RenderNormalview.normalmap_from_pictures_uniforms["invertR"].value = 1;
		}
		
		NMO_NormalMap.createNormalMap();
	};

	this.invertGreen = function(){
		this.invert_green = !this.invert_green;
		if (this.invert_green){
			NMO_RenderNormalview.normalmap_uniforms["invertG"].value = -1;
			NMO_RenderNormalview.normalmap_from_pictures_uniforms["invertG"].value = -1;
		}
		else{
			NMO_RenderNormalview.normalmap_uniforms["invertG"].value = 1;
			NMO_RenderNormalview.normalmap_from_pictures_uniforms["invertG"].value = 1;
		}
		
		NMO_NormalMap.createNormalMap();
	};

	this.invertSource = function(){
		this.invert_source = !this.invert_source;
		if (!this.invert_source){
			NMO_RenderNormalview.normalmap_uniforms["invertH"].value = 1;
			NMO_RenderNormalview.normalmap_from_pictures_uniforms["invertH"].value = 1;
		}
		else{
			NMO_RenderNormalview.normalmap_uniforms["invertH"].value = -1;
			NMO_RenderNormalview.normalmap_from_pictures_uniforms["invertH"].value = -1;
		}

		NMO_NormalMap.createNormalMap();
	};

	this.heightOffset = function(){
		this.height_offset = !this.height_offset;
		if (this.height_offset){
			NMO_RenderNormalview.normalmap_uniforms["heightOffset"].value = 0;
			NMO_RenderNormalview.normalmap_from_pictures_uniforms["heightOffset"].value = 0;
		}
		else{
			NMO_RenderNormalview.normalmap_uniforms["heightOffset"].value = 1;
			NMO_RenderNormalview.normalmap_from_pictures_uniforms["heightOffset"].value = 1;
		}
		
		NMO_NormalMap.createNormalMap();
	};

	this.setNormalSetting = function(element, v, initial){
		if (element == "blur_sharp"){
			smoothing = v;
			NMO_RenderNormalview.gaussian_shader_y.uniforms["v"].value = v / NMO_FileDrop.height_image.naturalWidth / 5;
			NMO_RenderNormalview.gaussian_shader_x.uniforms["h"].value = v / NMO_FileDrop.height_image.naturalHeight / 5;
			//NMO_RenderNormalview.gaussian_shader.uniforms["sigma"].value = v / NMO_FileDrop.height_image.naturalHeight / 5;
		}
		
		else if (element == "strength"){
			strength = v;
			NMO_RenderNormalview.normalmap_uniforms["dz"].value = 1.0 / v * (1.0 + Math.pow(2.0, document.getElementById('level_nmb').value));
			NMO_RenderNormalview.normalmap_from_pictures_uniforms["dz"].value = 1.0 / v * (1.0 + Math.pow(2.0, document.getElementById('level_nmb').value));
		}
		
		else if (element == "level"){
			level = v;
			NMO_RenderNormalview.normalmap_uniforms["dz"].value = 1.0 / document.getElementById('strength_nmb').value * (1.0 + Math.pow(2.0, v));
			NMO_RenderNormalview.normalmap_from_pictures_uniforms["dz"].value = 1.0 / document.getElementById('strength_nmb').value * (1.0 + Math.pow(2.0, v));
		}

		else if (element == "type"){
			normal_type = v;
			if (v == "sobel")
				NMO_RenderNormalview.normalmap_uniforms["type"].value = 0;
			else
				NMO_RenderNormalview.normalmap_uniforms["type"].value = 1;
		}

		if (typeof initial === 'undefined')
			NMO_NormalMap.createNormalMap();
	};
}

猜你喜欢

转载自blog.csdn.net/Angelloveyatou/article/details/130731729
今日推荐