{"id":16308,"date":"2025-10-02T09:15:16","date_gmt":"2025-10-02T00:15:16","guid":{"rendered":"http:\/\/www.gisdeveloper.co.kr\/?p=16308"},"modified":"2025-10-02T09:18:36","modified_gmt":"2025-10-02T00:18:36","slug":"%ec%97%ac%eb%9f%ac-%ea%b0%9c%ec%9d%98-%ed%85%8d%ec%8a%a4%ec%b3%90-%eb%8d%b0%ec%9d%b4%ed%84%b0%eb%a5%bc-%ed%95%9c%ea%ba%bc%eb%b2%88%ec%97%90-%ec%89%90%ec%9d%b4%eb%8d%94%eb%a1%9c-%ec%a0%84%eb%8b%ac","status":"publish","type":"post","link":"http:\/\/www.gisdeveloper.co.kr\/?p=16308","title":{"rendered":"\uc5ec\ub7ec \uac1c\uc758 \ud14d\uc2a4\uccd0 \ub370\uc774\ud130\ub97c \ud55c\uaebc\ubc88\uc5d0 \uc250\uc774\ub354\ub85c \uc804\ub2ec\ud558\uae30"},"content":{"rendered":"<p>\ud14d\uc2a4\ucc98\ub294 \uc774\ubbf8\uc9c0 \uadf8 \uc774\uc0c1\uc758 \uac00\uce58\ub97c \uac00\uc9c4 \ub370\uc774\ud130\uc774\ub2e4. \ud14d\uc2a4\uccd0\ub97c \uc250\uc774\ub354\ub85c \ub118\uae38\ub54c \ud754\ud788 \ud558\ub098\uc529 \ub118\uae30\ub294 \uacbd\uc6b0\uac00 \ud754\ud55c\ub370, \uac00\ub2a5\ud558\ub2e4\uba74 \ud55c\uaebc\ubc88\uc5d0 \ub118\uae30\ub294\uac8c \uc18d\ub3c4\uba74\uc5d0\uc11c \ud6e8\uc52c \uc774\ub4dd\uc774\ub2e4. \uc989, \ud14d\uc2a4\uccd0 \ubc30\uc5f4 \ud0c0\uc785(sampler2DArray)\uc73c\ub85c \uc250\uc774\ub354\uc5d0\uc11c \ubc1b\ub3c4\ub85d \ud55c\ub2e4. \uc774\ub97c \uc704\ud574 three.js \uac1c\ubc1c\uc790\ub294 \ub2e4\uc74c\uacfc \uac19\uc740 \ud3b8\ub9ac\ud55c \ud074\ub798\uc2a4\ub97c \uc81c\uacf5\ud55c\ub2e4.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\">\r\nclass TextureAtlas {\r\n  \/\/ \ub108\ubb34 \uae38\uc5b4\uc11c \uc804\uccb4 \ucf54\ub4dc\ub294 \uc774 \uae00 \ub9e8 \uc544\ub798 \ucc38\uc870\r\n}\r\n<\/pre>\n<p>\uc0ac\uc6a9 \ubc29\ubc95\uc744 \ubcf4\uc790. \uba3c\uc800 \uc804\ub2ec\ud560 \uc5ec\ub7ec\uac1c\uc758 \uc774\ubbf8\uc9c0 \ud30c\uc77c\uc744 \uc704\uc758 \ud074\ub798\uc2ac\ub974 \ud1b5\ud574 \ubd88\ub7ec\uc628\ub2e4.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\">\r\nconst textures = new TextureAtlas();\r\ndiffuse.Load('myTextures', [\r\n  '.\/textures\/a.png',\r\n  '.\/textures\/b.png',\r\n  '.\/textures\/c.png',\r\n  ...\r\n]);\r\n\r\ntextures.onLoad = () => {\r\n  myShaderMaterial.uniforms.uniformData.value = textures.Info['myTextures'].atlas;\r\n};\r\n<\/pre>\n<p>\uc250\uc774\ub354 \ucf54\ub4dc\uc5d0\uc11c\ub294 uniformData\ub77c\ub294 \uc774\ub984\uc758 uniform \ub370\uc774\ud130\ub97c \ub2e4\uc74c\ucc98\ub7fc \ucc38\uc870\ud560 \uc218 \uc788\uac8c \ub41c\ub2e4.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"glsl\">\r\nuniform sampler2DArray uniformData;\r\n\r\nmain() {\r\n  vec4 color = texture2D(uniformData, vec3(uv, 0.0));\r\n\r\n  ...\r\n}\r\n<\/pre>\n<p>texture2D\uc758 2\ubc88\uc9f8 \uc778\uc790\uac00 3\ucc28\uc6d0 \ub370\uc774\ud130\uc778\ub370, 3\ubc88\uc9f8 \ucc28\uc6d0\uc758 \uac12\uc744 \ud1b5\ud574 \uc5b4\ub5a4 \ud14d\uc2a4\ucc98 \ub370\uc774\ud130\ub97c \uc0ac\uc6a9\ud560\uc9c0\ub97c \uc9c0\uc815\ud558\ub294 \uc778\ub371\uc2a4\uc774\ub2e4. 0\uc774\uba74 \uccab\ubc88\uc9f8 \ud14d\uc2a4\uccd0 \ub370\uc774\ud130\uc778 a.png, 2\uc774\uba74 c.png\ub77c\ub294 \uc2dd\uc774\ub2e4. \uc27d\uc8e0?<\/p>\n<p>\ub108\ubb34 \uae38\uc5b4 \ubcf4\uc5ec\uc8fc\uc9c0 \uc54a\uc558\ub358 TextureAtlas\uc758 \uc804\uccb4 \ucf54\ub4dc\ub294 \ub2e4\uc74c\uacfc \uac19\ub2e4.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\">\r\nfunction _GetImageData(image) {\r\n  const canvas = document.createElement('canvas');\r\n  canvas.width = image.width;\r\n  canvas.height = image.height;\r\n\r\n  const context = canvas.getContext('2d');\r\n  context.translate(0, image.height);\r\n  context.scale(1, -1);\r\n  context.drawImage(image, 0, 0);\r\n\r\n  return context.getImageData( 0, 0, image.width, image.height );\r\n}\r\n\r\nclass TextureAtlas {\r\n  constructor() {\r\n    this.create_();\r\n    this.onLoad = () => {};\r\n  }\r\n\r\n  Load(atlas, names) {\r\n    this.loadAtlas_(atlas, names);\r\n  }\r\n\r\n  create_() {\r\n    this.manager_ = new THREE.LoadingManager();\r\n    this.loader_ = new THREE.TextureLoader(this.manager_);\r\n    this.textures_ = {};\r\n\r\n    this.manager_.onLoad = () => {\r\n      this.onLoad_();\r\n    };\r\n  }\r\n\r\n  get Info() {\r\n    return this.textures_;\r\n  }\r\n\r\n  onLoad_() {\r\n    for (let k in this.textures_) {\r\n      let X = null;\r\n      let Y = null;\r\n      const atlas = this.textures_[k];\r\n      let data = null;\r\n\r\n      for (let t = 0; t < atlas.textures.length; t++) {\r\n        const loader = atlas.textures[t];\r\n        const curData = loader();\r\n\r\n        const h = curData.height;\r\n        const w = curData.width;\r\n\r\n        if (X === null) {\r\n          X = w;\r\n          Y = h;\r\n          data = new Uint8Array(atlas.textures.length * 4 * X * Y);\r\n        }\r\n\r\n        if (w !== X || h !== Y) {\r\n          console.error('Texture dimensions do not match');\r\n          return;\r\n        }\r\n        const offset = t * (4 * w * h);\r\n\r\n        data.set(curData.data, offset);\r\n      }\r\n\r\n      const diffuse = new THREE.DataArrayTexture(data, X, Y, atlas.textures.length);\r\n      diffuse.format = THREE.RGBAFormat;\r\n      diffuse.type = THREE.UnsignedByteType;\r\n      diffuse.minFilter = THREE.LinearMipMapLinearFilter;\r\n      diffuse.magFilter = THREE.LinearFilter;\r\n      diffuse.wrapS = THREE.ClampToEdgeWrapping;\r\n      diffuse.wrapT = THREE.ClampToEdgeWrapping;\r\n      \/\/ diffuse.wrapS = THREE.RepeatWrapping;\r\n      \/\/ diffuse.wrapT = THREE.RepeatWrapping;\r\n      diffuse.generateMipmaps = true;\r\n      diffuse.needsUpdate = true;\r\n\r\n      atlas.atlas = diffuse;\r\n    }\r\n\r\n    this.onLoad();\r\n  }\r\n\r\n  loadType_(t) {\r\n    if (typeof(t) == 'string') {\r\n      const texture = this.loader_.load(t);\r\n      return () => {\r\n        return _GetImageData(texture.image);\r\n      };\r\n    } else {\r\n      return () => {\r\n        return t;\r\n      };\r\n    }\r\n  }\r\n\r\n  loadAtlas_(atlas, names) {\r\n    this.textures_[atlas] = {\r\n      textures: names.map(n => this.loadType_(n))\r\n    };\r\n  }\r\n}\r\n<\/pre>\n<p>\ubb50.. \ubcc4\uac70 \uc5c6\uc8e0?<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\ud14d\uc2a4\ucc98\ub294 \uc774\ubbf8\uc9c0 \uadf8 \uc774\uc0c1\uc758 \uac00\uce58\ub97c \uac00\uc9c4 \ub370\uc774\ud130\uc774\ub2e4. \ud14d\uc2a4\uccd0\ub97c \uc250\uc774\ub354\ub85c \ub118\uae38\ub54c \ud754\ud788 \ud558\ub098\uc529 \ub118\uae30\ub294 \uacbd\uc6b0\uac00 \ud754\ud55c\ub370, \uac00\ub2a5\ud558\ub2e4\uba74 \ud55c\uaebc\ubc88\uc5d0 \ub118\uae30\ub294\uac8c \uc18d\ub3c4\uba74\uc5d0\uc11c \ud6e8\uc52c \uc774\ub4dd\uc774\ub2e4. \uc989, \ud14d\uc2a4\uccd0 \ubc30\uc5f4 \ud0c0\uc785(sampler2DArray)\uc73c\ub85c \uc250\uc774\ub354\uc5d0\uc11c \ubc1b\ub3c4\ub85d \ud55c\ub2e4. \uc774\ub97c \uc704\ud574 three.js \uac1c\ubc1c\uc790\ub294 \ub2e4\uc74c\uacfc \uac19\uc740 \ud3b8\ub9ac\ud55c \ud074\ub798\uc2a4\ub97c \uc81c\uacf5\ud55c\ub2e4. class TextureAtlas { \/\/ \ub108\ubb34 \uae38\uc5b4\uc11c \uc804\uccb4 \ucf54\ub4dc\ub294 \uc774 \uae00 \ub9e8 \uc544\ub798 \ucc38\uc870 } \uc0ac\uc6a9 \ubc29\ubc95\uc744 \ubcf4\uc790. \uba3c\uc800 &hellip; <\/p>\n<p class=\"link-more\"><a href=\"http:\/\/www.gisdeveloper.co.kr\/?p=16308\" class=\"more-link\">\ub354 \ubcf4\uae30<span class=\"screen-reader-text\"> &#8220;\uc5ec\ub7ec \uac1c\uc758 \ud14d\uc2a4\uccd0 \ub370\uc774\ud130\ub97c \ud55c\uaebc\ubc88\uc5d0 \uc250\uc774\ub354\ub85c \uc804\ub2ec\ud558\uae30&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[153,145],"tags":[],"class_list":["post-16308","post","type-post","status-publish","format-standard","hentry","category-shader","category-three-js"],"_links":{"self":[{"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=\/wp\/v2\/posts\/16308","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=16308"}],"version-history":[{"count":4,"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=\/wp\/v2\/posts\/16308\/revisions"}],"predecessor-version":[{"id":16313,"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=\/wp\/v2\/posts\/16308\/revisions\/16313"}],"wp:attachment":[{"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=16308"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=16308"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=16308"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}