{"id":16444,"date":"2025-12-02T16:42:23","date_gmt":"2025-12-02T07:42:23","guid":{"rendered":"http:\/\/www.gisdeveloper.co.kr\/?p=16444"},"modified":"2025-12-02T17:04:29","modified_gmt":"2025-12-02T08:04:29","slug":"gpu%ec%97%90%ec%84%9c-%ec%b2%98%eb%a6%ac%eb%90%98%eb%8a%94-storagebufferattribute-%ec%83%9d%ec%84%b1","status":"publish","type":"post","link":"http:\/\/www.gisdeveloper.co.kr\/?p=16444","title":{"rendered":"GPU\uc5d0\uc11c \ucc98\ub9ac\ub418\ub294 StorageBufferAttribute \uc0dd\uc131 (Compute Shader)"},"content":{"rendered":"<p>\uc218\ubc31\ub9cc\uac1c\uc758 BOIDS\uc5d0 \ub300\ud55c \ub370\uc774\ud130\ub97c \ube60\ub974\uac8c \ucc98\ub9ac\ud558\uae30 \uc704\ud55c \ubc29\uc548 \uc911 \uac00\uc7a5 \ucd5c\uace0\uc758 \uc120\ud0dd\uc740 GPU\uc5d0\uc11c \ucc98\ub9ac\ud558\ub294 \uac83\uc785\ub2c8\ub2e4. \ucc98\ub9ac\ud558\uace0\uc790 \ud558\ub294 BOID\uc758 \uac1c\uc218\uac00 \ub2e4\uc74c\uacfc \uac19\ub2e4\uace0 \ud560\ub54c \ucd5c\uc885\uc801\uc73c\ub85c GPU\uc5d0\uc11c \uc77d\uace0 \uc4f8 \uc218 \uc788\ub294 StorageBufferAttribute \uac1d\uccb4\ub97c \uc0dd\uc131\ud558\ub294 \uacfc\uc815\uc744 \ucf54\ub4dc\ub85c \uc815\ub9ac\ud569\ub2c8\ub2e4.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\">\r\nconst BOIDS = 9;\r\n<\/pre>\n<p>BOID\uc758 \uc704\uce58\uac12\uc5d0 \ub300\ud55c \ub370\uc774\ud130\ub77c\uace0 \ud55c\ub2e4\uba74 \uba3c\uc800 Float32Array \uac1d\uccb4\ub97c \uc0dd\uc131\ud569\ub2c8\ub2e4.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\">\r\nconst positionArray = new Float32Array(BOIDS * 3);\r\n<\/pre>\n<p>\uc774 \ubc30\uc5f4 \uac1d\uccb4\uc5d0 BOID\uc758 \uc815\ubcf4\ub97c \ucc44\uc6c0\ub2c8\ub2e4. \uc544\ub798\ub294 \uaca9\uc790 \ud615\ud0dc\ub85c BOID\ub4e4\uc774 \ubc30\uce58\ub418\ub3c4\ub85d \ud569\ub2c8\ub2e4.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\">\r\nconst cellSize = 0.5;\r\n\r\nfor (let i = 0; i < BOIDS; i++) {\r\n  const offset = i * 3;\r\n  const row = (i % 3) - 1;\r\n  const col = (~~(i \/ 3)) - 1;\r\n\r\n  positionArray[offset + 0] = col * cellSize;\r\n  positionArray[offset + 1] = row * cellSize;\r\n  positionArray[offset + 2] = 0; \/\/ \uc774\ubbf8 0\uc73c\ub85c \ucd08\uae30\ud654 \ub418\uc5b4 \uc788\uc73c\ubbc0\ub85c \ubd88\ud544\uc694\ud568 \ucf54\ub4dc\r\n}\r\n<\/pre>\n<p>\uc774\ub807\uac8c \ub9cc\ub4e0 \ubc30\uc5f4 \uac1d\uccb4\ub97c StorageBufferAttribute\ub85c \uc0dd\uc131\ud558\uae30 \uc704\ud55c \ucf54\ub4dc\ub294 \ub2e4\uc74c\uacfc \uac19\uc2b5\ub2c8\ub2e4.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\">\r\nconst positionStorage = attributeArray(positionArray, \"vec3\");\r\n<\/pre>\n<p>\uc774\uc81c positionStorage\ub97c \ud1b5\ud574 GPU\uc5d0\uc11c BOID\uc758 \uc704\uce58\ub97c \uc77d\uace0 \uc4f8 \uc218 \uc788\uc2b5\ub2c8\ub2e4.<\/p>\n<p>GPU\ub97c \ud1b5\ud574 positionStorage\ub97c \uc77d\ub294 TSL \ucf54\ub4dc \uc608\uc2dc\ub294 \ub2e4\uc74c\uacfc \uac19\uc2b5\ub2c8\ub2e4.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\">\r\nconst flockVertexTSL = Fn(() => {\r\n  const instanceID = attribute(\"instanceID\");\r\n  const finalVert = modelWorldMatrix.mul(\r\n    positionLocal.add(positionStorage.element(instanceID))\r\n  ).toConst();\r\n  return cameraProjectionMatrix.mul(cameraViewMatrix).mul(finalVert);\r\n});\r\n<\/pre>\n<p>2\ubc88 \ucf54\ub4dc\ub294 positionStorage\uc5d0 \uc800\uc7a5\ub41c BOID \uc911 \uc77d\uc744 \ub140\uc11d\uc5d0 \ub300\ud55c \uc778\ub371\uc2a4\uac12\uc785\ub2c8\ub2e4. \uc704\uc758 \uacbd\uc6b0\ub294 \ubcc4\ub3c4\uc758 attribute\uc5d0 BOID\uc758 \uc778\ub371\uc2a4\ub97c \uc800\uc7a5\ud574 \uc0ac\uc6a9\ud558\uace0 \uc788\uc2b5\ub2c8\ub2e4. flockVerteTSL\uc740 \uc7ac\uc9c8\uc758 vertexNode\uc5d0 \uc9c0\uc815\ud558\uba74 \ub429\ub2c8\ub2e4.<\/p>\n<p>\ub9cc\uc57d positionStorage\uc5d0 \uc800\uc7a5\ub41c BOID \ub4e4\uc758 \uc704\uce58\ub97c \ubcc0\uacbd\ud558\uace0\uc790 \ud560\ub54c GPU\uc5d0\uc11c \uc218\ud589\ud560 \uc218 \uc788\uace0 \uc774\ub97c Compute Shader\ub97c \ud1b5\ud574 \ub3d9\uc2dc\uc5d0 \ucc98\ub9ac\uac00 \uac00\ub2a5\ud569\ub2c8\ub2e4. \uc544\ub798\ub294 \ud574\ub2f9 \ucc98\ub9ac\ub97c \uc218\ud589\ud558\ub294 GPU\uc5d0\uc11c \uc2e4\ud589\ub418\ub294 \ud568\uc218\uc758 \uc608\uc2dc\uc785\ub2c8\ub2e4.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\">\r\nconst radius = uniform(float(0.7));\r\nconst delta = uniform(float(1));\r\n\r\nconst computePosition = Fn(() => {\r\n  const PI2 = float(6.2832).toConst();\r\n  const theta = PI2.div(BOIDS).toConst();\r\n  const idx = instanceIndex.toConst();\r\n  const posx = cos(time.add(theta.mul(idx))).mul(radius).toConst();\r\n  const posy = sin(time.add(theta.mul(idx))).mul(radius).toConst();\r\n  const cellSize = .5;\r\n  const row = float(idx).mod(3.0).sub(1.0).toConst();\r\n  const col = floor(float(idx).div(3.0)).sub(1.0).toConst();\r\n  const v1 = vec3(posx, posy, 0).toConst();\r\n  const v2 = vec3(col.mul(cellSize), row.mul(cellSize), 0).toConst();\r\n  positionStorage.element(idx).assign(mix(v2, v1, delta));\r\n})().compute(BOIDS);\r\n<\/pre>\n<p>\uc704\uc758 \ucf54\ub4dc \uc911 instanceIndex\ub294 \ucc98\ub9ac\ub418\uace0 \uc788\ub294 BOID\uc758 \uc778\ub371\uc2a4\uc785\ub2c8\ub2e4. \ucf54\ub4dc\uc758 \ub9c8\uc9c0\ub9c9\uc5d0 compute \ub9e4\uc11c\ub4dc\ub97c \ud1b5\ud574 \uc778\uc790\ub85c \ubc1b\uc740 \uac1c\uc218\ub9cc\ud07c \ubcd1\ub82c\ub85c \ub3d9\uc2dc\uc5d0 \uc2e4\ud589\ub418\uc5b4\uc9c8 \uc218 \uc788\ub3c4\ub85d \ud574\uc90d\ub2c8\ub2e4. \uc704\uc5d0\uc11c \uc815\uc758\ub41c computePosition\ub294 (\ud544\uc694\ud558\ub2e4\uba74 \ud544\ub4dc\ud654\ud558\uc5ec) \ub9e4 \ud504\ub808\uc784\ub9c8\ub2e4 \ub80c\ub354\ub9c1\ub420 \ub54c \uc2e4\ud589\ud574\uc918\uc57c \ud558\uba70 \uc544\ub798\ub294 \uadf8 \ucf54\ub4dc \uc608\uc2dc\uc785\ub2c8\ub2e4.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\">\r\nthis._renderer.compute(this._computePosition);\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>\uc218\ubc31\ub9cc\uac1c\uc758 BOIDS\uc5d0 \ub300\ud55c \ub370\uc774\ud130\ub97c \ube60\ub974\uac8c \ucc98\ub9ac\ud558\uae30 \uc704\ud55c \ubc29\uc548 \uc911 \uac00\uc7a5 \ucd5c\uace0\uc758 \uc120\ud0dd\uc740 GPU\uc5d0\uc11c \ucc98\ub9ac\ud558\ub294 \uac83\uc785\ub2c8\ub2e4. \ucc98\ub9ac\ud558\uace0\uc790 \ud558\ub294 BOID\uc758 \uac1c\uc218\uac00 \ub2e4\uc74c\uacfc \uac19\ub2e4\uace0 \ud560\ub54c \ucd5c\uc885\uc801\uc73c\ub85c GPU\uc5d0\uc11c \uc77d\uace0 \uc4f8 \uc218 \uc788\ub294 StorageBufferAttribute \uac1d\uccb4\ub97c \uc0dd\uc131\ud558\ub294 \uacfc\uc815\uc744 \ucf54\ub4dc\ub85c \uc815\ub9ac\ud569\ub2c8\ub2e4. const BOIDS = 9; BOID\uc758 \uc704\uce58\uac12\uc5d0 \ub300\ud55c \ub370\uc774\ud130\ub77c\uace0 \ud55c\ub2e4\uba74 \uba3c\uc800 Float32Array \uac1d\uccb4\ub97c \uc0dd\uc131\ud569\ub2c8\ub2e4. const positionArray = new Float32Array(BOIDS * 3); \uc774 &hellip; <\/p>\n<p class=\"link-more\"><a href=\"http:\/\/www.gisdeveloper.co.kr\/?p=16444\" class=\"more-link\">\ub354 \ubcf4\uae30<span class=\"screen-reader-text\"> &#8220;GPU\uc5d0\uc11c \ucc98\ub9ac\ub418\ub294 StorageBufferAttribute \uc0dd\uc131 (Compute Shader)&#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-16444","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\/16444","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=16444"}],"version-history":[{"count":8,"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=\/wp\/v2\/posts\/16444\/revisions"}],"predecessor-version":[{"id":16449,"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=\/wp\/v2\/posts\/16444\/revisions\/16449"}],"wp:attachment":[{"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=16444"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=16444"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=16444"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}