three.js + imgui-js 项目中的场景渲染问题
Scene rendering issues in three.js + imgui-js project
我有一个项目正在使用 Three.js
和 imgui-js
。我正在尝试更新到每个版本的最新版本,但我 运行 遇到了问题(它们最近一次更新是在 2020 年 2 月左右)。
初始化我调用的两个库:
await ImGui.default();
ImGui.CreateContext();
ImGui_Impl.Init(canvas);
ImGui.StyleColorsDark();
const clear_color = new ImGui.ImVec4(0.3, 0.3, 0.3, 1.00);
const renderer = new THREE.WebGLRenderer({ canvas: canvas });
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.gammaFactor = 2.2;
renderer.physicallyCorrectLights = true;
renderer.outputEncoding = THREE.sRGBEncoding;
然后我在三个场景中添加一些对象:
const scene = new THREE.Scene();
let floorDim = 1000;
var grid = new THREE.GridHelper(floorDim, 200, 'orange', 'white');
grid.name = "grid";
grid.material.opacity = 1.0;
grid.material.transparent = true;
grid.material.color.convertGammaToLinear(2.2);
grid.position.set(0, 2, 0);
scene.add(grid);
var subgrid = new THREE.GridHelper(floorDim, 600, 'grey', 'grey');
subgrid.name = "subgrid";
subgrid.material.opacity = 1.0;
subgrid.material.color.convertGammaToLinear(2.2);
subgrid.material.transparent = true;
subgrid.position.set(0, 1, 0);
scene.add(subgrid);
const light = new THREE.DirectionalLight(0xffffff, 0.8);
light.position.set(0, 100, -50);
light.lookAt(new THREE.Vector3(0, 0, 0));
scene.add(light);
const box_1_mesh = new THREE.Mesh(new THREE.BoxGeometry(5, 5, 5), new THREE.MeshLambertMaterial({ color:0x970000 }));
box_1_mesh.position.set(0, 5, 0);
scene.add(box_1_mesh);
const box_2_mesh = new THREE.Mesh(new THREE.BoxGeometry(5, 5, 5), new THREE.MeshLambertMaterial({ color:0x333000 }));
box_2_mesh.position.set(-2, 6, 7);
scene.add(box_2_mesh);
const camera = new THREE.PerspectiveCamera(50, canvas.width / canvas.height, 2, 10000);
camera.position.set(0, 10, -25);
camera.updateProjectionMatrix();
camera.lookAt(0, 0, 0);
scene.add(camera);
并调用如下所示的更新循环:
function _loop(time) {
ImGui_Impl.NewFrame(time);
ImGui.NewFrame();
ImGui.SetNextWindowPos(new ImGui.ImVec2(20, 20), ImGui.Cond.FirstUseEver);
ImGui.SetNextWindowSize(new ImGui.ImVec2(294, 140), ImGui.Cond.FirstUseEver);
ImGui.Begin("Visblility Toggles:");
ImGui.Checkbox("box_1 (near)", (value = box_1_mesh.visible) => box_1_mesh.visible = value);
ImGui.Checkbox("box_2 (distant)", (value = box_2_mesh.visible) => box_2_mesh.visible = value);
ImGui.Checkbox("grid", (value = grid.visible) => grid.visible = value);
ImGui.Checkbox("subgrid", (value = subgrid.visible) => subgrid.visible = value);
ImGui.End();
ImGui.EndFrame();
ImGui.Render();
renderer.setClearColor(new THREE.Color(clear_color.x, clear_color.y, clear_color.z), clear_color.w);
renderer.setSize(canvas.width, canvas.height);
camera.aspect = canvas.width / canvas.height;
camera.updateProjectionMatrix();
renderer.render(scene, camera);
ImGui_Impl.RenderDrawData(ImGui.GetDrawData());
renderer.state.reset();
window.requestAnimationFrame(_loop);
}
更新到这些库的最新版本后,我遇到了场景中的对象未按预期渲染的问题。
例如,我将 2 GridHelpers
添加到场景中,但由于某种原因只显示了一个。此外,如果在场景中切换不同 Three
对象的可见性,例如切换其中一个网格 off/on 的显示,当切换回对象时不会再次显示(有时其他物体消失)。
发生的另一个问题是,更复杂的网格材质会有意想不到的透明度,但对于我在本例中添加的简单框,该问题似乎不会发生。虽然,框的外观根据是否进行了 ImGui_Impl.RenderDrawData
调用而改变可能是相关的。
我发现,如果我注释掉对 ImGui_Impl.RenderDrawData(ImGui.GetDrawData())
的调用,场景会按预期显示,同时显示两个网格助手,所以我怀疑两者之间可能存在一些内部冲突webGl
的库用法。尽管我绝对有可能设置不正确,或者我错过了一个需要的电话。
为了帮助演示该问题,我创建了一个复制该问题的片段:https://codepen.io/bpeake/pen/KKNNQre。
(async function() {
await ImGui.default();
const canvas = document.getElementById("output");
const devicePixelRatio = window.devicePixelRatio || 1;
canvas.width = canvas.scrollWidth * devicePixelRatio;
canvas.height = canvas.scrollHeight * devicePixelRatio;
window.addEventListener("resize", () => {
const devicePixelRatio = window.devicePixelRatio || 1;
canvas.width = canvas.scrollWidth * devicePixelRatio;
canvas.height = canvas.scrollHeight * devicePixelRatio;
});
ImGui.CreateContext();
ImGui_Impl.Init(canvas);
ImGui.StyleColorsDark();
const clear_color = new ImGui.ImVec4(0.3, 0.3, 0.3, 1.00);
const renderer = new THREE.WebGLRenderer({ canvas: canvas });
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.gammaFactor = 2.2;
renderer.physicallyCorrectLights = true;
renderer.outputEncoding = THREE.sRGBEncoding;
const scene = new THREE.Scene();
let floorDim = 1000;
var grid = new THREE.GridHelper(floorDim, 200, 'orange', 'white');
grid.name = "grid";
grid.material.opacity = 1.0;
grid.material.transparent = true;
grid.material.color.convertGammaToLinear(2.2);
grid.position.set(0, 2, 0);
scene.add(grid);
var subgrid = new THREE.GridHelper(floorDim, 600, 'grey', 'grey');
subgrid.name = "subgrid";
subgrid.material.opacity = 1.0;
subgrid.material.color.convertGammaToLinear(2.2);
subgrid.material.transparent = true;
subgrid.position.set(0, 1, 0);
scene.add(subgrid);
const light = new THREE.DirectionalLight(0xffffff, 0.8);
light.position.set(0, 100, -50);
light.lookAt(new THREE.Vector3(0, 0, 0));
scene.add(light);
const box_1_mesh = new THREE.Mesh(new THREE.BoxGeometry(5, 5, 5), new THREE.MeshLambertMaterial({ color:0x970000 }));
box_1_mesh.position.set(0, 5, 0);
scene.add(box_1_mesh);
const box_2_mesh = new THREE.Mesh(new THREE.BoxGeometry(5, 5, 5), new THREE.MeshLambertMaterial({ color:0x333000 }));
box_2_mesh.position.set(-2, 6, 7);
scene.add(box_2_mesh);
const camera = new THREE.PerspectiveCamera(50, canvas.width / canvas.height, 2, 10000);
camera.position.set(0, 10, -25);
camera.updateProjectionMatrix();
camera.lookAt(0, 0, 0);
scene.add(camera);
window.requestAnimationFrame(_loop);
function _loop(time) {
ImGui_Impl.NewFrame(time);
ImGui.NewFrame();
ImGui.SetNextWindowPos(new ImGui.ImVec2(20, 20), ImGui.Cond.FirstUseEver);
ImGui.SetNextWindowSize(new ImGui.ImVec2(294, 140), ImGui.Cond.FirstUseEver);
ImGui.Begin("Visblility Toggles:");
ImGui.Checkbox("box_1 (near)", (value = box_1_mesh.visible) => box_1_mesh.visible = value);
ImGui.Checkbox("box_2 (distant)", (value = box_2_mesh.visible) => box_2_mesh.visible = value);
ImGui.Checkbox("grid", (value = grid.visible) => grid.visible = value);
ImGui.Checkbox("subgrid", (value = subgrid.visible) => subgrid.visible = value);
ImGui.End();
ImGui.EndFrame();
ImGui.Render();
renderer.setClearColor(new THREE.Color(clear_color.x, clear_color.y, clear_color.z), clear_color.w);
renderer.setSize(canvas.width, canvas.height);
camera.aspect = canvas.width / canvas.height;
camera.updateProjectionMatrix();
renderer.render(scene, camera);
ImGui_Impl.RenderDrawData(ImGui.GetDrawData());
renderer.state.reset();
window.requestAnimationFrame(_loop);
}
})();
#output {
position: absolute;
top: 0px;
right: 0px;
width: 100%;
height: 100%;
z-index: 1;
}
<script>
// emu localStorage otherwise ImGUI fails because S.O blocks localStorage
{
const localStorageStorage = new Map();
const localStorage = {
getItem(k) { return localStorageStorage.get(k); },
setItem(k,v) { return localStorageStorage.set(k, v); },
};
Object.defineProperty(window, 'localStorage', {
get() { return localStorage; }
});
}
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r125/three.min.js"></script>
<script src="https://flyover.github.io/imgui-js/dist/imgui.umd.js"></script>
<script src="https://flyover.github.io/imgui-js/dist/imgui_impl.umd.js"></script>
<script src="https://flyover.github.io/nanovg-js/dist/nanovg.umd.js"></script>
<canvas tabindex="0" id="output"></canvas>
我设置的 imgui-js
或 three-js
有什么问题吗?关于我可以做什么以使 ImGui_Impl.RenderDrawData
调用不影响我的 three.js
场景的渲染的任何想法?
问题是 imgui-js 破坏了属性状态。
你可能想考虑 运行 imgui-js 在另一个 canvas 覆盖在
three.js canvas,每个都有自己的 WebGL 上下文。这样他们就不用担心了。
这是一个快速破解方法
const gl = renderer.getContext();
window.vao = window.vao || gl.createVertexArray();
const oldVao = gl.getParameter(gl.VERTEX_ARRAY_BINDING);
gl.bindVertexArray(vao);
ImGui_Impl.RenderDrawData(ImGui.GetDrawData());
gl.bindVertexArray(oldVao);
但该 hack 仅适用于 WebGL2。要完全保存和恢复丢失的状态并不难,但处理 WebGL1、扩展和 WebGL2 可能需要 50-80 行代码。
我提交了 issue here with an example PR
(async function() {
await ImGui.default();
const canvas = document.getElementById("output");
const devicePixelRatio = window.devicePixelRatio || 1;
canvas.width = canvas.scrollWidth * devicePixelRatio;
canvas.height = canvas.scrollHeight * devicePixelRatio;
window.addEventListener("resize", () => {
const devicePixelRatio = window.devicePixelRatio || 1;
canvas.width = canvas.scrollWidth * devicePixelRatio;
canvas.height = canvas.scrollHeight * devicePixelRatio;
});
ImGui.CreateContext();
ImGui_Impl.Init(canvas);
ImGui.StyleColorsDark();
const clear_color = new ImGui.ImVec4(0.3, 0.3, 0.3, 1.00);
const renderer = new THREE.WebGLRenderer({ canvas: canvas });
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.gammaFactor = 2.2;
renderer.physicallyCorrectLights = true;
renderer.outputEncoding = THREE.sRGBEncoding;
const scene = new THREE.Scene();
let floorDim = 1000;
var grid = new THREE.GridHelper(floorDim, 200, 'orange', 'white');
grid.name = "grid";
grid.material.opacity = 1.0;
grid.material.transparent = true;
grid.material.color.convertGammaToLinear(2.2);
grid.position.set(0, 2, 0);
scene.add(grid);
var subgrid = new THREE.GridHelper(floorDim, 600, 'grey', 'grey');
subgrid.name = "subgrid";
subgrid.material.opacity = 1.0;
subgrid.material.color.convertGammaToLinear(2.2);
subgrid.material.transparent = true;
subgrid.position.set(0, 1, 0);
scene.add(subgrid);
const light = new THREE.DirectionalLight(0xffffff, 0.8);
light.position.set(0, 100, -50);
light.lookAt(new THREE.Vector3(0, 0, 0));
scene.add(light);
const box_1_mesh = new THREE.Mesh(new THREE.BoxGeometry(5, 5, 5), new THREE.MeshLambertMaterial({ color:0x970000 }));
box_1_mesh.position.set(0, 5, 0);
scene.add(box_1_mesh);
const box_2_mesh = new THREE.Mesh(new THREE.BoxGeometry(5, 5, 5), new THREE.MeshLambertMaterial({ color:0x333000 }));
box_2_mesh.position.set(-2, 6, 7);
scene.add(box_2_mesh);
const camera = new THREE.PerspectiveCamera(50, canvas.width / canvas.height, 2, 10000);
camera.position.set(0, 10, -25);
camera.updateProjectionMatrix();
camera.lookAt(0, 0, 0);
scene.add(camera);
setTimeout(() => {
grid.visible = false;
}, 1000);
setTimeout(() => {
grid.visible = true;
}, 2000);
setTimeout(() => {
console.log(grid.visible);
}, 2500);
window.requestAnimationFrame(_loop);
function _loop(time) {
ImGui_Impl.NewFrame(time);
ImGui.NewFrame();
ImGui.SetNextWindowPos(new ImGui.ImVec2(20, 20), ImGui.Cond.FirstUseEver);
ImGui.SetNextWindowSize(new ImGui.ImVec2(294, 140), ImGui.Cond.FirstUseEver);
ImGui.Begin("Visblility Toggles:");
ImGui.Checkbox("box_1 (near)", (value = box_1_mesh.visible) => box_1_mesh.visible = value);
ImGui.Checkbox("box_2 (distant)", (value = box_2_mesh.visible) => box_2_mesh.visible = value);
ImGui.Checkbox("grid", (value = grid.visible) => grid.visible = value);
ImGui.Checkbox("subgrid", (value = subgrid.visible) => subgrid.visible = value);
ImGui.End();
ImGui.EndFrame();
ImGui.Render();
renderer.setClearColor(new THREE.Color(clear_color.x, clear_color.y, clear_color.z), clear_color.w);
renderer.setSize(canvas.width, canvas.height);
camera.aspect = canvas.width / canvas.height;
camera.updateProjectionMatrix();
renderer.render(scene, camera);
const gl = renderer.getContext();
window.vao = window.vao || gl.createVertexArray();
const oldVao = gl.getParameter(gl.VERTEX_ARRAY_BINDING);
gl.bindVertexArray(vao);
ImGui_Impl.RenderDrawData(ImGui.GetDrawData());
gl.bindVertexArray(oldVao);
renderer.state.reset();
window.requestAnimationFrame(_loop);
}
})();
#output {
position: absolute;
top: 0px;
right: 0px;
width: 100%;
height: 100%;
z-index: 1;
}
<script>
// emu localStorage otherwise ImGUI fails because S.O blocks localStorage
{
const localStorageStorage = new Map();
const localStorage = {
getItem(k) { return localStorageStorage.get(k); },
setItem(k,v) { return localStorageStorage.set(k, v); },
};
Object.defineProperty(window, 'localStorage', {
get() { return localStorage; }
});
}
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r125/three.js"></script>
<script src="https://flyover.github.io/imgui-js/dist/imgui.umd.js"></script>
<script src="https://flyover.github.io/imgui-js/dist/imgui_impl.umd.js"></script>
<script src="https://flyover.github.io/nanovg-js/dist/nanovg.umd.js"></script>
<canvas tabindex="0" id="output"></canvas>
我有一个项目正在使用 Three.js
和 imgui-js
。我正在尝试更新到每个版本的最新版本,但我 运行 遇到了问题(它们最近一次更新是在 2020 年 2 月左右)。
初始化我调用的两个库:
await ImGui.default();
ImGui.CreateContext();
ImGui_Impl.Init(canvas);
ImGui.StyleColorsDark();
const clear_color = new ImGui.ImVec4(0.3, 0.3, 0.3, 1.00);
const renderer = new THREE.WebGLRenderer({ canvas: canvas });
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.gammaFactor = 2.2;
renderer.physicallyCorrectLights = true;
renderer.outputEncoding = THREE.sRGBEncoding;
然后我在三个场景中添加一些对象:
const scene = new THREE.Scene();
let floorDim = 1000;
var grid = new THREE.GridHelper(floorDim, 200, 'orange', 'white');
grid.name = "grid";
grid.material.opacity = 1.0;
grid.material.transparent = true;
grid.material.color.convertGammaToLinear(2.2);
grid.position.set(0, 2, 0);
scene.add(grid);
var subgrid = new THREE.GridHelper(floorDim, 600, 'grey', 'grey');
subgrid.name = "subgrid";
subgrid.material.opacity = 1.0;
subgrid.material.color.convertGammaToLinear(2.2);
subgrid.material.transparent = true;
subgrid.position.set(0, 1, 0);
scene.add(subgrid);
const light = new THREE.DirectionalLight(0xffffff, 0.8);
light.position.set(0, 100, -50);
light.lookAt(new THREE.Vector3(0, 0, 0));
scene.add(light);
const box_1_mesh = new THREE.Mesh(new THREE.BoxGeometry(5, 5, 5), new THREE.MeshLambertMaterial({ color:0x970000 }));
box_1_mesh.position.set(0, 5, 0);
scene.add(box_1_mesh);
const box_2_mesh = new THREE.Mesh(new THREE.BoxGeometry(5, 5, 5), new THREE.MeshLambertMaterial({ color:0x333000 }));
box_2_mesh.position.set(-2, 6, 7);
scene.add(box_2_mesh);
const camera = new THREE.PerspectiveCamera(50, canvas.width / canvas.height, 2, 10000);
camera.position.set(0, 10, -25);
camera.updateProjectionMatrix();
camera.lookAt(0, 0, 0);
scene.add(camera);
并调用如下所示的更新循环:
function _loop(time) {
ImGui_Impl.NewFrame(time);
ImGui.NewFrame();
ImGui.SetNextWindowPos(new ImGui.ImVec2(20, 20), ImGui.Cond.FirstUseEver);
ImGui.SetNextWindowSize(new ImGui.ImVec2(294, 140), ImGui.Cond.FirstUseEver);
ImGui.Begin("Visblility Toggles:");
ImGui.Checkbox("box_1 (near)", (value = box_1_mesh.visible) => box_1_mesh.visible = value);
ImGui.Checkbox("box_2 (distant)", (value = box_2_mesh.visible) => box_2_mesh.visible = value);
ImGui.Checkbox("grid", (value = grid.visible) => grid.visible = value);
ImGui.Checkbox("subgrid", (value = subgrid.visible) => subgrid.visible = value);
ImGui.End();
ImGui.EndFrame();
ImGui.Render();
renderer.setClearColor(new THREE.Color(clear_color.x, clear_color.y, clear_color.z), clear_color.w);
renderer.setSize(canvas.width, canvas.height);
camera.aspect = canvas.width / canvas.height;
camera.updateProjectionMatrix();
renderer.render(scene, camera);
ImGui_Impl.RenderDrawData(ImGui.GetDrawData());
renderer.state.reset();
window.requestAnimationFrame(_loop);
}
更新到这些库的最新版本后,我遇到了场景中的对象未按预期渲染的问题。
例如,我将 2 GridHelpers
添加到场景中,但由于某种原因只显示了一个。此外,如果在场景中切换不同 Three
对象的可见性,例如切换其中一个网格 off/on 的显示,当切换回对象时不会再次显示(有时其他物体消失)。
发生的另一个问题是,更复杂的网格材质会有意想不到的透明度,但对于我在本例中添加的简单框,该问题似乎不会发生。虽然,框的外观根据是否进行了 ImGui_Impl.RenderDrawData
调用而改变可能是相关的。
我发现,如果我注释掉对 ImGui_Impl.RenderDrawData(ImGui.GetDrawData())
的调用,场景会按预期显示,同时显示两个网格助手,所以我怀疑两者之间可能存在一些内部冲突webGl
的库用法。尽管我绝对有可能设置不正确,或者我错过了一个需要的电话。
为了帮助演示该问题,我创建了一个复制该问题的片段:https://codepen.io/bpeake/pen/KKNNQre。
(async function() {
await ImGui.default();
const canvas = document.getElementById("output");
const devicePixelRatio = window.devicePixelRatio || 1;
canvas.width = canvas.scrollWidth * devicePixelRatio;
canvas.height = canvas.scrollHeight * devicePixelRatio;
window.addEventListener("resize", () => {
const devicePixelRatio = window.devicePixelRatio || 1;
canvas.width = canvas.scrollWidth * devicePixelRatio;
canvas.height = canvas.scrollHeight * devicePixelRatio;
});
ImGui.CreateContext();
ImGui_Impl.Init(canvas);
ImGui.StyleColorsDark();
const clear_color = new ImGui.ImVec4(0.3, 0.3, 0.3, 1.00);
const renderer = new THREE.WebGLRenderer({ canvas: canvas });
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.gammaFactor = 2.2;
renderer.physicallyCorrectLights = true;
renderer.outputEncoding = THREE.sRGBEncoding;
const scene = new THREE.Scene();
let floorDim = 1000;
var grid = new THREE.GridHelper(floorDim, 200, 'orange', 'white');
grid.name = "grid";
grid.material.opacity = 1.0;
grid.material.transparent = true;
grid.material.color.convertGammaToLinear(2.2);
grid.position.set(0, 2, 0);
scene.add(grid);
var subgrid = new THREE.GridHelper(floorDim, 600, 'grey', 'grey');
subgrid.name = "subgrid";
subgrid.material.opacity = 1.0;
subgrid.material.color.convertGammaToLinear(2.2);
subgrid.material.transparent = true;
subgrid.position.set(0, 1, 0);
scene.add(subgrid);
const light = new THREE.DirectionalLight(0xffffff, 0.8);
light.position.set(0, 100, -50);
light.lookAt(new THREE.Vector3(0, 0, 0));
scene.add(light);
const box_1_mesh = new THREE.Mesh(new THREE.BoxGeometry(5, 5, 5), new THREE.MeshLambertMaterial({ color:0x970000 }));
box_1_mesh.position.set(0, 5, 0);
scene.add(box_1_mesh);
const box_2_mesh = new THREE.Mesh(new THREE.BoxGeometry(5, 5, 5), new THREE.MeshLambertMaterial({ color:0x333000 }));
box_2_mesh.position.set(-2, 6, 7);
scene.add(box_2_mesh);
const camera = new THREE.PerspectiveCamera(50, canvas.width / canvas.height, 2, 10000);
camera.position.set(0, 10, -25);
camera.updateProjectionMatrix();
camera.lookAt(0, 0, 0);
scene.add(camera);
window.requestAnimationFrame(_loop);
function _loop(time) {
ImGui_Impl.NewFrame(time);
ImGui.NewFrame();
ImGui.SetNextWindowPos(new ImGui.ImVec2(20, 20), ImGui.Cond.FirstUseEver);
ImGui.SetNextWindowSize(new ImGui.ImVec2(294, 140), ImGui.Cond.FirstUseEver);
ImGui.Begin("Visblility Toggles:");
ImGui.Checkbox("box_1 (near)", (value = box_1_mesh.visible) => box_1_mesh.visible = value);
ImGui.Checkbox("box_2 (distant)", (value = box_2_mesh.visible) => box_2_mesh.visible = value);
ImGui.Checkbox("grid", (value = grid.visible) => grid.visible = value);
ImGui.Checkbox("subgrid", (value = subgrid.visible) => subgrid.visible = value);
ImGui.End();
ImGui.EndFrame();
ImGui.Render();
renderer.setClearColor(new THREE.Color(clear_color.x, clear_color.y, clear_color.z), clear_color.w);
renderer.setSize(canvas.width, canvas.height);
camera.aspect = canvas.width / canvas.height;
camera.updateProjectionMatrix();
renderer.render(scene, camera);
ImGui_Impl.RenderDrawData(ImGui.GetDrawData());
renderer.state.reset();
window.requestAnimationFrame(_loop);
}
})();
#output {
position: absolute;
top: 0px;
right: 0px;
width: 100%;
height: 100%;
z-index: 1;
}
<script>
// emu localStorage otherwise ImGUI fails because S.O blocks localStorage
{
const localStorageStorage = new Map();
const localStorage = {
getItem(k) { return localStorageStorage.get(k); },
setItem(k,v) { return localStorageStorage.set(k, v); },
};
Object.defineProperty(window, 'localStorage', {
get() { return localStorage; }
});
}
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r125/three.min.js"></script>
<script src="https://flyover.github.io/imgui-js/dist/imgui.umd.js"></script>
<script src="https://flyover.github.io/imgui-js/dist/imgui_impl.umd.js"></script>
<script src="https://flyover.github.io/nanovg-js/dist/nanovg.umd.js"></script>
<canvas tabindex="0" id="output"></canvas>
我设置的 imgui-js
或 three-js
有什么问题吗?关于我可以做什么以使 ImGui_Impl.RenderDrawData
调用不影响我的 three.js
场景的渲染的任何想法?
问题是 imgui-js 破坏了属性状态。
你可能想考虑 运行 imgui-js 在另一个 canvas 覆盖在 three.js canvas,每个都有自己的 WebGL 上下文。这样他们就不用担心了。
这是一个快速破解方法
const gl = renderer.getContext();
window.vao = window.vao || gl.createVertexArray();
const oldVao = gl.getParameter(gl.VERTEX_ARRAY_BINDING);
gl.bindVertexArray(vao);
ImGui_Impl.RenderDrawData(ImGui.GetDrawData());
gl.bindVertexArray(oldVao);
但该 hack 仅适用于 WebGL2。要完全保存和恢复丢失的状态并不难,但处理 WebGL1、扩展和 WebGL2 可能需要 50-80 行代码。
我提交了 issue here with an example PR
(async function() {
await ImGui.default();
const canvas = document.getElementById("output");
const devicePixelRatio = window.devicePixelRatio || 1;
canvas.width = canvas.scrollWidth * devicePixelRatio;
canvas.height = canvas.scrollHeight * devicePixelRatio;
window.addEventListener("resize", () => {
const devicePixelRatio = window.devicePixelRatio || 1;
canvas.width = canvas.scrollWidth * devicePixelRatio;
canvas.height = canvas.scrollHeight * devicePixelRatio;
});
ImGui.CreateContext();
ImGui_Impl.Init(canvas);
ImGui.StyleColorsDark();
const clear_color = new ImGui.ImVec4(0.3, 0.3, 0.3, 1.00);
const renderer = new THREE.WebGLRenderer({ canvas: canvas });
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.gammaFactor = 2.2;
renderer.physicallyCorrectLights = true;
renderer.outputEncoding = THREE.sRGBEncoding;
const scene = new THREE.Scene();
let floorDim = 1000;
var grid = new THREE.GridHelper(floorDim, 200, 'orange', 'white');
grid.name = "grid";
grid.material.opacity = 1.0;
grid.material.transparent = true;
grid.material.color.convertGammaToLinear(2.2);
grid.position.set(0, 2, 0);
scene.add(grid);
var subgrid = new THREE.GridHelper(floorDim, 600, 'grey', 'grey');
subgrid.name = "subgrid";
subgrid.material.opacity = 1.0;
subgrid.material.color.convertGammaToLinear(2.2);
subgrid.material.transparent = true;
subgrid.position.set(0, 1, 0);
scene.add(subgrid);
const light = new THREE.DirectionalLight(0xffffff, 0.8);
light.position.set(0, 100, -50);
light.lookAt(new THREE.Vector3(0, 0, 0));
scene.add(light);
const box_1_mesh = new THREE.Mesh(new THREE.BoxGeometry(5, 5, 5), new THREE.MeshLambertMaterial({ color:0x970000 }));
box_1_mesh.position.set(0, 5, 0);
scene.add(box_1_mesh);
const box_2_mesh = new THREE.Mesh(new THREE.BoxGeometry(5, 5, 5), new THREE.MeshLambertMaterial({ color:0x333000 }));
box_2_mesh.position.set(-2, 6, 7);
scene.add(box_2_mesh);
const camera = new THREE.PerspectiveCamera(50, canvas.width / canvas.height, 2, 10000);
camera.position.set(0, 10, -25);
camera.updateProjectionMatrix();
camera.lookAt(0, 0, 0);
scene.add(camera);
setTimeout(() => {
grid.visible = false;
}, 1000);
setTimeout(() => {
grid.visible = true;
}, 2000);
setTimeout(() => {
console.log(grid.visible);
}, 2500);
window.requestAnimationFrame(_loop);
function _loop(time) {
ImGui_Impl.NewFrame(time);
ImGui.NewFrame();
ImGui.SetNextWindowPos(new ImGui.ImVec2(20, 20), ImGui.Cond.FirstUseEver);
ImGui.SetNextWindowSize(new ImGui.ImVec2(294, 140), ImGui.Cond.FirstUseEver);
ImGui.Begin("Visblility Toggles:");
ImGui.Checkbox("box_1 (near)", (value = box_1_mesh.visible) => box_1_mesh.visible = value);
ImGui.Checkbox("box_2 (distant)", (value = box_2_mesh.visible) => box_2_mesh.visible = value);
ImGui.Checkbox("grid", (value = grid.visible) => grid.visible = value);
ImGui.Checkbox("subgrid", (value = subgrid.visible) => subgrid.visible = value);
ImGui.End();
ImGui.EndFrame();
ImGui.Render();
renderer.setClearColor(new THREE.Color(clear_color.x, clear_color.y, clear_color.z), clear_color.w);
renderer.setSize(canvas.width, canvas.height);
camera.aspect = canvas.width / canvas.height;
camera.updateProjectionMatrix();
renderer.render(scene, camera);
const gl = renderer.getContext();
window.vao = window.vao || gl.createVertexArray();
const oldVao = gl.getParameter(gl.VERTEX_ARRAY_BINDING);
gl.bindVertexArray(vao);
ImGui_Impl.RenderDrawData(ImGui.GetDrawData());
gl.bindVertexArray(oldVao);
renderer.state.reset();
window.requestAnimationFrame(_loop);
}
})();
#output {
position: absolute;
top: 0px;
right: 0px;
width: 100%;
height: 100%;
z-index: 1;
}
<script>
// emu localStorage otherwise ImGUI fails because S.O blocks localStorage
{
const localStorageStorage = new Map();
const localStorage = {
getItem(k) { return localStorageStorage.get(k); },
setItem(k,v) { return localStorageStorage.set(k, v); },
};
Object.defineProperty(window, 'localStorage', {
get() { return localStorage; }
});
}
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r125/three.js"></script>
<script src="https://flyover.github.io/imgui-js/dist/imgui.umd.js"></script>
<script src="https://flyover.github.io/imgui-js/dist/imgui_impl.umd.js"></script>
<script src="https://flyover.github.io/nanovg-js/dist/nanovg.umd.js"></script>
<canvas tabindex="0" id="output"></canvas>